import { BaseEntity } from '@edr/api-common';
import { Column, Entity, Index, JoinColumn, ManyToOne } from 'typeorm';
import { Booking } from '../../bookings/entities/booking.entity';
import { Contract } from './contract.entity';

export const MILESTONE_STATUSES = ['PENDING', 'COMPLETED', 'SKIPPED'] as const;
export type MilestoneStatus = (typeof MILESTONE_STATUSES)[number];

export const MILESTONE_OWNER_REGIONS = ['ET', 'DJ', 'OPS', 'CUST'] as const;
export type MilestoneOwnerRegion = (typeof MILESTONE_OWNER_REGIONS)[number];

export const CUSTOMS_RISK_LEVELS = ['GREEN', 'YELLOW', 'RED'] as const;
export type CustomsRiskLevel = (typeof CUSTOMS_RISK_LEVELS)[number];

/**
 * One customs risk decision. Risk stays correctable until duty is advised off
 * it, and the level is customer-visible, so every assignment is kept rather than
 * overwritten — a disputed level needs to show what was set, by whom, and when.
 */
export interface RiskAssignmentRecord {
  level: CustomsRiskLevel;
  /** The level this replaced; absent on the first assignment. */
  previousLevel?: CustomsRiskLevel;
  assignedAt: string;
  assignedByUserId?: string | null;
  /** Display name resolved at assignment time, so the trail never shows a UUID. */
  assignedBy?: string | null;
  note?: string | null;
}

/**
 * Structured payload some milestones carry beyond a plain note (doc §11.3):
 * - RISK_ASSIGNED → `riskLevel` (current) + `riskHistory` (every assignment)
 * - DUTY_TAXES_ADVISED → `dutyAmount`, `dutyCurrency`, `declarationSerial`
 * Stored on the milestone so the timeline can render the value inline.
 */
export interface MilestoneMetadata {
  riskLevel?: CustomsRiskLevel;
  /**
   * Append-only, oldest first. `riskLevel` is the current value and always
   * equals the last entry's `level`.
   */
  riskHistory?: RiskAssignmentRecord[];
  dutyAmount?: number;
  dutyCurrency?: string;
  declarationSerial?: string;
  /** When the gate pass was physically granted (GL DJ captures the time). */
  gatepassAt?: string;
}

/**
 * A GL clearance milestone (18–23 per direction). Pre-booking milestones attach
 * to contract_id + clearance_cycle_id; post-booking milestones to booking_id.
 * See §5.12, §5.16, §11.3.
 */
@Entity({ schema: 'freight', name: 'clearance_milestones' })
@Index(['bookingId'])
@Index(['contractId'])
@Index(['ownerRegion', 'status'])
export class ClearanceMilestone extends BaseEntity {
  @Column({ name: 'booking_id', type: 'uuid', nullable: true })
  bookingId?: string | null;

  @ManyToOne(() => Booking, { nullable: true, onDelete: 'CASCADE' })
  @JoinColumn({ name: 'booking_id' })
  booking?: Booking | null;

  @Column({ name: 'contract_id', type: 'uuid', nullable: true })
  contractId?: string | null;

  @ManyToOne(() => Contract, { nullable: true, onDelete: 'CASCADE' })
  @JoinColumn({ name: 'contract_id' })
  contract?: Contract | null;

  @Column({ name: 'clearance_cycle_id', type: 'uuid', nullable: true })
  clearanceCycleId?: string | null;

  @Column({ name: 'milestone_code', type: 'varchar', length: 64 })
  milestoneCode!: string;

  @Column({ name: 'milestone_label', type: 'varchar', length: 255 })
  milestoneLabel!: string;

  @Column({ name: 'status', type: 'varchar', length: 20, default: 'PENDING' })
  status!: MilestoneStatus;

  @Column({ name: 'owner_region', type: 'varchar', length: 5, nullable: true })
  ownerRegion?: MilestoneOwnerRegion | null;

  @Column({ name: 'triggered_by_doc', type: 'boolean', default: false })
  triggeredByDoc!: boolean;

  @Column({ name: 'triggered_at', type: 'timestamptz', nullable: true })
  triggeredAt?: Date | null;

  @Column({ name: 'triggered_by_user_id', type: 'uuid', nullable: true })
  triggeredByUserId?: string | null;

  @Column({ name: 'note', type: 'text', nullable: true })
  note?: string | null;

  @Column({ name: 'metadata', type: 'jsonb', nullable: true })
  metadata?: MilestoneMetadata | null;

  @Column({ name: 'sort_order', type: 'smallint', default: 0 })
  sortOrder!: number;
}
