package complaint

import (
	"time"

	"gorm.io/gorm"

	flightdomain "wucher/internal/domain/flight"
	helicopter "wucher/internal/domain/helicopter"
	"wucher/internal/shared/pkg/uuidv7"
)

const (
	MELSeverityNonMEL int8 = 0
	MELSeverityA      int8 = 1
	MELSeverityB      int8 = 2
	MELSeverityC      int8 = 3
	MELSeverityD      int8 = 4
)

const (
	StatusPendingMEL   = "pending_mel"
	StatusActiveNonMEL = "active_non_mel"
	StatusActiveMEL    = "active_mel"
	StatusServiced     = "serviced"
)

var melGraceDays = map[int8]int{
	MELSeverityA: 1,
	MELSeverityB: 3,
	MELSeverityC: 10,
	MELSeverityD: 120,
}

type ListFilter struct {
	Search        string
	DateFrom      string
	DateTo        string
	Person        string
	HelicopterID  []byte
	FlightID      []byte
	HoldItemsOnly bool
}

func MELGraceDays(severity int8) int { return melGraceDays[severity] }

type Complaint struct {
	ID           []byte `gorm:"type:binary(16);primaryKey;column:id"`
	HelicopterID []byte `gorm:"type:binary(16);not null;index;column:helicopter_id"`
	FlightID     []byte `gorm:"type:binary(16);index;column:flight_id"`

	Description           string    `gorm:"type:text;not null;column:description"`
	ReportedBy            []byte    `gorm:"type:binary(16);not null;column:reported_by"`
	ReportedAt            time.Time `gorm:"type:datetime(3);not null;column:reported_at"`
	AircraftHoursAtReport *string   `gorm:"type:varchar(20);column:aircraft_hours_at_report"`

	MELSeverity     int8       `gorm:"type:tinyint;not null;default:0;column:mel_severity"`
	MELClassifiedAt *time.Time `gorm:"type:datetime(3);column:mel_classified_at"`
	MELClassifiedBy []byte     `gorm:"type:binary(16);column:mel_classified_by"`

	IsNSR        bool       `gorm:"type:boolean;not null;default:false;column:is_nsr"`
	NSRDecidedAt *time.Time `gorm:"type:datetime(3);column:nsr_decided_at"`
	NSRDecidedBy []byte     `gorm:"type:binary(16);column:nsr_decided_by"`
	NSRReason    *string    `gorm:"type:text;column:nsr_reason"`

	ActionTaken        *string `gorm:"type:text;column:action_taken"`
	AircraftHoursAtFix *string `gorm:"type:varchar(20);column:aircraft_hours_at_fix"`

	FixedAt       *time.Time `gorm:"type:datetime(3);column:fixed_at"`
	FixedByEASAID []byte     `gorm:"type:binary(16);column:fixed_by_easa_id"`

	Helicopter *helicopter.Helicopter `gorm:"foreignKey:HelicopterID;references:ID"`
	Flight     *flightdomain.Flight   `gorm:"foreignKey:FlightID;references:ID;constraint:OnUpdate:CASCADE,OnDelete:SET NULL"`

	CreatedAt time.Time  `gorm:"type:datetime(3);column:created_at"`
	CreatedBy []byte     `gorm:"type:binary(16);column:created_by"`
	UpdatedAt time.Time  `gorm:"type:datetime(3);column:updated_at"`
	UpdatedBy []byte     `gorm:"type:binary(16);column:updated_by"`
	DeletedAt *time.Time `gorm:"type:datetime(3);index;column:deleted_at"`
	DeletedBy []byte     `gorm:"type:binary(16);column:deleted_by"`
}

func (Complaint) TableName() string { return "complaints" }

func (c *Complaint) BeforeCreate(_ *gorm.DB) error {
	if len(c.ID) == 0 {
		c.ID = uuidv7.MustBytes()
	}
	return nil
}

func (c *Complaint) Status() string {
	if c == nil {
		return StatusActiveNonMEL
	}
	if c.FixedAt != nil {
		return StatusServiced
	}
	// mel_severity is optional at creation; until it is classified (mel_classified_at set)
	// the complaint is "pending_mel" — its severity value (0) is a default, not "Non-MEL".
	if c.MELClassifiedAt == nil {
		return StatusPendingMEL
	}
	if c.MELSeverity > 0 {
		return StatusActiveMEL
	}
	return StatusActiveNonMEL
}

func (c *Complaint) MELDeadline() *time.Time {
	if c == nil || c.MELSeverity <= 0 {
		return nil
	}
	grace := MELGraceDays(c.MELSeverity)
	if grace <= 0 || c.ReportedAt.IsZero() {
		return nil
	}
	// MEL grace is measured in days: A=1, B=3, C=10, D=120 days from report.
	deadline := c.ReportedAt.Add(time.Duration(grace) * 24 * time.Hour)
	return &deadline
}

func (c *Complaint) IsMELAOG(now time.Time) bool {
	if c == nil || c.IsNSR {
		return false
	}
	deadline := c.MELDeadline()
	if deadline == nil {
		return false
	}
	return !now.Before(*deadline)
}

// IsGrounding reports whether this complaint currently grounds the aircraft (AOG).
// Returning to service requires a formal release: only a Non-Safety Release (NSR /
// MEL deferral) or a signed EASA release (CRS, sets FixedAt) lifts the grounding.
// Recording action_taken alone does NOT lift it — corrective work is not a release.
//
// A pending (not-yet-classified) complaint does NOT ground: an unassessed report is not
// yet a grounding defect. Grounding starts at classification — NON-MEL grounds
// immediately, MEL A–D grounds once its grace deadline lapses.
func (c *Complaint) IsGrounding(now time.Time) bool {
	if c == nil || c.IsNSR || c.FixedAt != nil {
		return false
	}
	if c.MELClassifiedAt == nil {
		return false
	}
	if c.MELSeverity <= 0 {
		return true
	}
	return c.IsMELAOG(now)
}
