package pgtype

import (
	
	
	
	

	
)

type TimeScanner interface {
	ScanTime(v Time) error
}

type TimeValuer interface {
	TimeValue() (Time, error)
}

// Time represents the PostgreSQL time type. The PostgreSQL time is a time of day without time zone.
//
// Time is represented as the number of microseconds since midnight in the same way that PostgreSQL does. Other time
// and date types in pgtype can use time.Time as the underlying representation. However, pgtype.Time type cannot due
// to needing to handle 24:00:00. time.Time converts that to 00:00:00 on the following day.
type Time struct {
	Microseconds int64 // Number of microseconds since midnight
	Valid        bool
}

func ( *Time) ( Time) error {
	* = 
	return nil
}

func ( Time) () (Time, error) {
	return , nil
}

// Scan implements the database/sql Scanner interface.
func ( *Time) ( any) error {
	if  == nil {
		* = Time{}
		return nil
	}

	switch src := .(type) {
	case string:
		return scanPlanTextAnyToTimeScanner{}.Scan([]byte(), )
	}

	return fmt.Errorf("cannot scan %T", )
}

// Value implements the database/sql/driver Valuer interface.
func ( Time) () (driver.Value, error) {
	if !.Valid {
		return nil, nil
	}

	,  := TimeCodec{}.PlanEncode(nil, 0, TextFormatCode, ).Encode(, nil)
	if  != nil {
		return nil, 
	}
	return string(), 
}

type TimeCodec struct{}

func (TimeCodec) ( int16) bool {
	return  == TextFormatCode ||  == BinaryFormatCode
}

func (TimeCodec) () int16 {
	return BinaryFormatCode
}

func (TimeCodec) ( *Map,  uint32,  int16,  any) EncodePlan {
	if ,  := .(TimeValuer); ! {
		return nil
	}

	switch  {
	case BinaryFormatCode:
		return encodePlanTimeCodecBinary{}
	case TextFormatCode:
		return encodePlanTimeCodecText{}
	}

	return nil
}

type encodePlanTimeCodecBinary struct{}

func (encodePlanTimeCodecBinary) ( any,  []byte) ( []byte,  error) {
	,  := .(TimeValuer).TimeValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	return pgio.AppendInt64(, .Microseconds), nil
}

type encodePlanTimeCodecText struct{}

func (encodePlanTimeCodecText) ( any,  []byte) ( []byte,  error) {
	,  := .(TimeValuer).TimeValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	 := .Microseconds
	 :=  / microsecondsPerHour
	 -=  * microsecondsPerHour
	 :=  / microsecondsPerMinute
	 -=  * microsecondsPerMinute
	 :=  / microsecondsPerSecond
	 -=  * microsecondsPerSecond

	 := fmt.Sprintf("%02d:%02d:%02d.%06d", , , , )

	return append(, ...), nil
}

func (TimeCodec) ( *Map,  uint32,  int16,  any) ScanPlan {

	switch  {
	case BinaryFormatCode:
		switch .(type) {
		case TimeScanner:
			return scanPlanBinaryTimeToTimeScanner{}
		}
	case TextFormatCode:
		switch .(type) {
		case TimeScanner:
			return scanPlanTextAnyToTimeScanner{}
		}
	}

	return nil
}

type scanPlanBinaryTimeToTimeScanner struct{}

func (scanPlanBinaryTimeToTimeScanner) ( []byte,  any) error {
	 := ().(TimeScanner)

	if  == nil {
		return .ScanTime(Time{})
	}

	if len() != 8 {
		return fmt.Errorf("invalid length for time: %v", len())
	}

	 := int64(binary.BigEndian.Uint64())

	return .ScanTime(Time{Microseconds: , Valid: true})
}

type scanPlanTextAnyToTimeScanner struct{}

func (scanPlanTextAnyToTimeScanner) ( []byte,  any) error {
	 := ().(TimeScanner)

	if  == nil {
		return .ScanTime(Time{})
	}

	 := string()

	if len() < 8 {
		return fmt.Errorf("cannot decode %v into Time", )
	}

	,  := strconv.ParseInt([0:2], 10, 64)
	if  != nil {
		return fmt.Errorf("cannot decode %v into Time", )
	}
	 :=  * microsecondsPerHour

	,  := strconv.ParseInt([3:5], 10, 64)
	if  != nil {
		return fmt.Errorf("cannot decode %v into Time", )
	}
	 +=  * microsecondsPerMinute

	,  := strconv.ParseInt([6:8], 10, 64)
	if  != nil {
		return fmt.Errorf("cannot decode %v into Time", )
	}
	 +=  * microsecondsPerSecond

	if len() > 9 {
		 := [9:]
		,  := strconv.ParseInt(, 10, 64)
		if  != nil {
			return fmt.Errorf("cannot decode %v into Time", )
		}

		for  := len();  < 6; ++ {
			 *= 10
		}

		 += 
	}

	return .ScanTime(Time{Microseconds: , Valid: true})
}

func ( TimeCodec) ( *Map,  uint32,  int16,  []byte) (driver.Value, error) {
	return codecDecodeToTextFormat(, , , , )
}

func ( TimeCodec) ( *Map,  uint32,  int16,  []byte) (any, error) {
	if  == nil {
		return nil, nil
	}

	var  Time
	 := codecScan(, , , , , &)
	if  != nil {
		return nil, 
	}
	return , nil
}