package pgtype

import (
	
	
	
	
	

	
)

const (
	microsecondsPerSecond = 1000000
	microsecondsPerMinute = 60 * microsecondsPerSecond
	microsecondsPerHour   = 60 * microsecondsPerMinute
	microsecondsPerDay    = 24 * microsecondsPerHour
	microsecondsPerMonth  = 30 * microsecondsPerDay
)

type IntervalScanner interface {
	ScanInterval(v Interval) error
}

type IntervalValuer interface {
	IntervalValue() (Interval, error)
}

type Interval struct {
	Microseconds int64
	Days         int32
	Months       int32
	Valid        bool
}

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

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

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

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

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

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

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

type IntervalCodec struct{}

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

func (IntervalCodec) () int16 {
	return BinaryFormatCode
}

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

	switch  {
	case BinaryFormatCode:
		return encodePlanIntervalCodecBinary{}
	case TextFormatCode:
		return encodePlanIntervalCodecText{}
	}

	return nil
}

type encodePlanIntervalCodecBinary struct{}

func (encodePlanIntervalCodecBinary) ( any,  []byte) ( []byte,  error) {
	,  := .(IntervalValuer).IntervalValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	 = pgio.AppendInt64(, .Microseconds)
	 = pgio.AppendInt32(, .Days)
	 = pgio.AppendInt32(, .Months)
	return , nil
}

type encodePlanIntervalCodecText struct{}

func (encodePlanIntervalCodecText) ( any,  []byte) ( []byte,  error) {
	,  := .(IntervalValuer).IntervalValue()
	if  != nil {
		return nil, 
	}

	if !.Valid {
		return nil, nil
	}

	if .Months != 0 {
		 = append(, strconv.FormatInt(int64(.Months), 10)...)
		 = append(, " mon "...)
	}

	if .Days != 0 {
		 = append(, strconv.FormatInt(int64(.Days), 10)...)
		 = append(, " day "...)
	}

	 := .Microseconds
	if  < 0 {
		 = -
		 = append(, '-')
	}

	 :=  / microsecondsPerHour
	 := ( % microsecondsPerHour) / microsecondsPerMinute
	 := ( % microsecondsPerMinute) / microsecondsPerSecond
	 :=  % microsecondsPerSecond

	 := fmt.Sprintf("%02d:%02d:%02d.%06d", , , , )
	 = append(, ...)
	return , nil
}

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

	switch  {
	case BinaryFormatCode:
		switch .(type) {
		case IntervalScanner:
			return scanPlanBinaryIntervalToIntervalScanner{}
		}
	case TextFormatCode:
		switch .(type) {
		case IntervalScanner:
			return scanPlanTextAnyToIntervalScanner{}
		}
	}

	return nil
}

type scanPlanBinaryIntervalToIntervalScanner struct{}

func (scanPlanBinaryIntervalToIntervalScanner) ( []byte,  any) error {
	 := ().(IntervalScanner)

	if  == nil {
		return .ScanInterval(Interval{})
	}

	if len() != 16 {
		return fmt.Errorf("Received an invalid size for a interval: %d", len())
	}

	 := int64(binary.BigEndian.Uint64())
	 := int32(binary.BigEndian.Uint32([8:]))
	 := int32(binary.BigEndian.Uint32([12:]))

	return .ScanInterval(Interval{Microseconds: , Days: , Months: , Valid: true})
}

type scanPlanTextAnyToIntervalScanner struct{}

func (scanPlanTextAnyToIntervalScanner) ( []byte,  any) error {
	 := ().(IntervalScanner)

	if  == nil {
		return .ScanInterval(Interval{})
	}

	var  int64
	var  int32
	var  int32

	 := strings.Split(string(), " ")

	for  := 0;  < len()-1;  += 2 {
		,  := strconv.ParseInt([], 10, 64)
		if  != nil {
			return fmt.Errorf("bad interval format")
		}

		switch [+1] {
		case "year", "years":
			 += int32( * 12)
		case "mon", "mons":
			 += int32()
		case "day", "days":
			 = int32()
		}
	}

	if len()%2 == 1 {
		 := strings.SplitN([len()-1], ":", 3)
		if len() != 3 {
			return fmt.Errorf("bad interval format")
		}

		var  bool
		if [0][0] == '-' {
			 = true
			[0] = [0][1:]
		}

		,  := strconv.ParseInt([0], 10, 64)
		if  != nil {
			return fmt.Errorf("bad interval hour format: %s", [0])
		}

		,  := strconv.ParseInt([1], 10, 64)
		if  != nil {
			return fmt.Errorf("bad interval minute format: %s", [1])
		}

		 := strings.SplitN([2], ".", 2)

		,  := strconv.ParseInt([0], 10, 64)
		if  != nil {
			return fmt.Errorf("bad interval second format: %s", [0])
		}

		var  int64
		if len() == 2 {
			,  = strconv.ParseInt([1], 10, 64)
			if  != nil {
				return fmt.Errorf("bad interval decimal format: %s", [1])
			}

			for  := 0;  < 6-len([1]); ++ {
				 *= 10
			}
		}

		 =  * microsecondsPerHour
		 +=  * microsecondsPerMinute
		 +=  * microsecondsPerSecond
		 += 

		if  {
			 = -
		}
	}

	return .ScanInterval(Interval{Months: , Days: , Microseconds: , Valid: true})
}

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

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

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