import type { BaseEntity } from "../common";

export * from "./dropdown_settings";
export * from "./file_upload_settings";
export * from "./overview";
export * from "./etrade";

export enum TradeDirection {
  IMPORT = "IMPORT",
  EXPORT = "EXPORT",
  BOTH = "BOTH",
}

export enum PriorityType {
  USD_PAYER = "USD_PAYER",
  RAIL_AND_FORWARDING = "RAIL_AND_FORWARDING",
  GOVERNMENT_ACCOUNT = "GOVERNMENT_ACCOUNT",
  HIGH_VOLUME_SHIPMENT = "HIGH_VOLUME_SHIPMENT",
}

/** Bonus applied to government bookings so they outrank commercial priority. */
export const GOVERNMENT_PRIORITY_BONUS = 50_000;

export interface GovernmentBookingFields {
  isGovernment: boolean;
  governmentInstitution?: string | null;
}

export enum ExceededAction {
  WARNING_ONLY = "WARNING_ONLY",
  HARD_BLOCK = "HARD_BLOCK",
}

export enum CalculationMethod {
  PER_TON = "PER_TON",
  FLAT_FEE = "FLAT_FEE",
  PERCENTAGE = "PERCENTAGE",
}

export enum FreightType {
  Container = "CONTAINER",
  Bulk = "BULK",
}

/**
 * Distinguishes a normal one-time booking from a general contract — an umbrella
 * commitment that is signed and paid once, then drawn down by many orders over
 * its period. Stored on the booking row.
 */
export enum BookingType {
  OneTime = "ONE_TIME",
  GeneralContract = "GENERAL_CONTRACT",
}

/**
 * How a cargo type's quantity is measured. Bulk cargo is weighed in tons,
 * break-bulk is counted per item. Containerised freight is always counted by
 * container and carries no unit-of-measure.
 */
export enum CargoUnitOfMeasure {
  PerTon = "PER_TON",
  PerItem = "PER_ITEM",
}

export enum BookingStatus {
  Draft = "DRAFT",
  Submitted = "SUBMITTED",
  ChangesRequested = "CHANGES_REQUESTED",
  PendingApproval = "PENDING_APPROVAL",
  ApprovedPendingSignature = "APPROVED_PENDING_SIGNATURE",
  Approved = "APPROVED",
  ContractReady = "CONTRACT_READY",
  SignedCustomer = "SIGNED_CUSTOMER",
  FullyExecuted = "FULLY_EXECUTED",
  PnrGenerated = "PNR_GENERATED",
  PaymentVerificationInProgress = "PAYMENT_VERIFICATION_IN_PROGRESS",
  /** Selected in a batch and notified to pay within the pay window. */
  SelectedForBatch = "SELECTED_FOR_BATCH",
  /** @deprecated Use SelectedForBatch */
  AwaitingPayment = "SELECTED_FOR_BATCH",
  /** Missed the 1h pay window — recoverable via move/cancel (no re-approval). */
  Expired = "EXPIRED",
  Paid = "PAID",
  InTransit = "IN_TRANSIT",
  Completed = "COMPLETED",
  Delivered = "DELIVERED",
  Rejected = "REJECTED",
  Cancelled = "CANCELLED",
  PendingConsolidation = "PENDING_CONSOLIDATION",
  Consolidated = "CONSOLIDATED",
  /** General contract: paid umbrella contract that is accepting drawdown orders. */
  ContractActive = "CONTRACT_ACTIVE",
  /** General contract: closed because its quantity was exhausted (or period elapsed). */
  ContractClosed = "CONTRACT_CLOSED",
}

export enum ConsignmentStatus {
  Pending = "PENDING",
  Loaded = "LOADED",
  InTransit = "IN_TRANSIT",
  AtDestination = "AT_DESTINATION",
  Delivered = "DELIVERED",
  Returned = "RETURNED",
}

export enum TrainStatus {
  Available = "AVAILABLE",
  Scheduled = "SCHEDULED",
  InService = "IN_SERVICE",
  UnderMaintenance = "UNDER_MAINTENANCE",
  OutOfService = "OUT_OF_SERVICE",
}

export enum CargoType {
  Container = "CONTAINER",
  BulkLiquid = "BULK_LIQUID",
  BulkDry = "BULK_DRY",
  General = "GENERAL",
  Refrigerated = "REFRIGERATED",
  Hazardous = "HAZARDOUS",
}

export enum PaymentStatus {
  Pending = "PENDING",
  Paid = "PAID",
  Overdue = "OVERDUE",
  Cancelled = "CANCELLED",
  Refunded = "REFUNDED",
}

export enum SchedulingStatus {
  NotScheduled = "NOT_SCHEDULED",
  Holding = "HOLDING",
  Eligible = "ELIGIBLE",
  Scheduled = "SCHEDULED",
  Dispatched = "DISPATCHED",
}

export enum TrainScheduleStatus {
  Draft = "DRAFT",
  Scheduled = "SCHEDULED",
  Dispatched = "DISPATCHED",
  Arrived = "ARRIVED",
  Cancelled = "CANCELLED",
}

/** Whether a schedule is still accepting / holding bookings (orthogonal to its operational status). */
export enum ScheduleBookingWindow {
  Open = "OPEN",
  Full = "FULL",
  Closed = "CLOSED",
}

export enum AllocationLoadType {
  Container = "CONTAINER",
  Bulk = "BULK",
}

export enum AllocationStatus {
  Planned = "PLANNED",
  Reserved = "RESERVED",
  Loaded = "LOADED",
  Departed = "DEPARTED",
}

export enum TrainSetWagonStatus {
  Planned = "PLANNED",
  Reserved = "RESERVED",
  Loaded = "LOADED",
  Departed = "DEPARTED",
}

export enum WagonStatus {
  Available = "AVAILABLE",
  Assigned = "ASSIGNED",
  Maintenance = "MAINTENANCE",
  Retired = "RETIRED",
}

export enum WagonReadiness {
  ImportReady = "IMPORT_READY",
  ExportReady = "EXPORT_READY",
}

export type ScheduleTradeDirection = "IMPORT" | "EXPORT" | "DOMESTIC";

export enum TrainCheckpointKind {
  Departed = "DEPARTED",
  Passed = "PASSED",
  Arrived = "ARRIVED",
}

export interface ITrainCheckpointEvent extends BaseEntity {
  trainScheduleId: string;
  yardId: string;
  sequenceNo: number;
  kind: TrainCheckpointKind;
  occurredAt: string;
  note?: string | null;
  recordedByUserId?: string | null;
}

export enum BulkPricingUnit {
  PerWagon = "PER_WAGON",
  PerTon = "PER_TON",
  PerItem = "PER_ITEM",
}

export type CustomerStatus = "Active" | "Pending" | "Inactive";
export type CustomerType = "Importer" | "Exporter" | "Supplier";

export interface ICustomer extends BaseEntity {
  userId: string;
  firstName: string;
  lastName: string;
  email: string;
  phone: string;
  companyName: string;
  companyEmail: string;
  companyPhone: string;
  companyLocation: string;
  companyAddress: string;
  contactPersonName: string;
  contactPersonPhone: string;
  tinNumber: string;
  vatNumber?: string | null;
  fanNumber: string;
  generalManagerName: string;
  generalManagerEmail: string;
  generalManagerPhone: string;
  poaName?: string | null;
  poaPhone?: string | null;
  poaAddress?: string | null;
  poaEmail?: string | null;
  poaLocation?: string | null;
  notes?: string | null;
}

export interface CreateCustomerDto {
  userId: string;
  firstName: string;
  lastName: string;
  email: string;
  phone: string;
  companyName: string;
  companyEmail: string;
  companyPhone: string;
  companyLocation: string;
  companyAddress: string;
  contactPersonName: string;
  contactPersonPhone: string;
  tinNumber: string;
  vatNumber: string;
  fanNumber: string;
  generalManagerName: string;
  generalManagerEmail: string;
  generalManagerPhone: string;
  poaName?: string;
  poaPhone?: string;
  poaAddress?: string;
  poaEmail?: string;
  poaLocation?: string;
  notes?: string;
}

export type UpdateCustomerDto = Partial<CreateCustomerDto>;

export interface ITrain extends BaseEntity {
  code: string;
  capacityTons: number;
  status: TrainStatus;
  notes?: string;
}

export interface ITrackingEvent extends BaseEntity {
  consignmentId: string;
  location: string;
  status: ConsignmentStatus;
  occurredAt: string;
  description?: string;
}

export interface IConsignment extends BaseEntity {
  bookingId: string;
  trackingNumber: string;
  cargoType: CargoType;
  weightKg: number;
  status: ConsignmentStatus;
  originStation: string;
  destinationStation: string;
}

/** One station along the train's corridor (origin → milestones → destination). */
export interface ITrackingStation {
  sequenceNo: number;
  yardId: string;
  label: string;
  code: string;
}

/** A logged checkpoint as the train passes a station. */
export interface ITrackingCheckpoint {
  id: string;
  sequenceNo: number;
  yardId: string;
  label: string | null;
  kind: TrainCheckpointKind;
  occurredAt: string;
  note: string | null;
}

/**
 * Customer-facing shipment tracking payload for a single booking, derived from
 * the train schedule the booking is assigned to and the live checkpoint log.
 *
 * `hasSchedule` is false when the booking has not been assigned to a train yet
 * (still pre-dispatch) — the UI shows a "not on the rails yet" state.
 */
export interface IBookingTracking {
  bookingId: string;
  bookingReference: string;
  hasSchedule: boolean;
  scheduleId: string | null;
  trainNumber: string | null;
  /** Operational status of the assigned schedule (DRAFT/SCHEDULED/DISPATCHED/ARRIVED). */
  scheduleStatus: TrainScheduleStatus | null;
  direction: string | null;
  origin: string | null;
  destination: string | null;
  /** Ordered stations forming the corridor. */
  stations: ITrackingStation[];
  /** Logged checkpoints, ordered by sequence then time. */
  checkpoints: ITrackingCheckpoint[];
  /** Highest reached station sequence (−1 = not departed). */
  currentSequenceNo: number;
  actualDepartureAt: string | null;
  actualArrivalAt: string | null;
  /** Planned departure/arrival from the schedule, used as ETA hints. */
  scheduledDepartureAt: string | null;
  scheduledArrivalAt: string | null;
}

export interface IYard extends BaseEntity {
  code: string;
  label: string;
  country: string;
  isActive: boolean;
  displayOrder: number;
}

export interface IBooking extends BaseEntity {
  reference: string;
  customerId: string;
  trainId?: string | null;
  status: BookingStatus;
  /** ONE_TIME for normal bookings; GENERAL_CONTRACT for umbrella contracts. */
  bookingType?: BookingType;
  /** General contracts only: when ordering closes (null until active / for one-time). */
  expiresAt?: string | null;
  /** Null for general contracts at creation — the date is chosen per order. */
  scheduledDate: string;
  totalAmount: number;
  /** Staff-adjusted total that overrides totalAmount for the customer, if set. */
  adjustedTotalAmount?: number | null;
  adjustedByStaffId?: string | null;
  adjustedAt?: string | null;
  adjustmentReason?: string | null;
  /**
   * Contract validity window set by the backoffice at the accept step. Valid
   * from contractValidFrom through contractValidUntil (validFrom + N days).
   */
  contractValidityDays?: number | null;
  contractValidFrom?: string | null;
  contractValidUntil?: string | null;
  paymentStatus: PaymentStatus;

  shippingLineId?: string | null;
  serviceTypeId: string;

  contractType: "NEW" | "RENEWAL";
  previousContractId?: string | null;
  serviceType: "RAIL_ONLY" | "RAIL_AND_FORWARDING";

  firstMileEnabled: boolean;
  firstMilePickupAddress?: string | null;
  firstMilePickupLat?: number | null;
  firstMilePickupLng?: number | null;
  lastMileEnabled: boolean;
  lastMileDeliveryAddress?: string | null;
  lastMileDeliveryLat?: number | null;
  lastMileDeliveryLng?: number | null;

  customsClearingEnabled?: boolean;
  customsClearingAgent?: string | null;

  equipmentReturn: "WITH_RETURN" | "WITHOUT_RETURN";
  originYard?: IYard | null;
  destinationYard?: IYard | null;
  cargoTotalWeightVgm: number;

  freightType: FreightType;
  freightSubtype?: string | null;

  isHazardous: boolean;
  isRefrigerated: boolean;

  tradeDirection: "IMPORT" | "EXPORT";
  paymentCurrency: string;
  consolidationPartnerId?: string | null;

  startDate?: string | null;
  endDate?: string | null;
  financialTerms?: string | null;

  /** When the batch engine picked this booking and opened the pay window. */
  selectedForBatchAt?: string | null;
  /** End of the pay window once the booking is SELECTED_FOR_BATCH. */
  paymentDeadline?: string | null;

  containers?: Array<{ type: string; qty: number; vgm: number }> | null;

  versionNumber: number;
  priorityScore: number;

  approvedByStaffId?: string | null;
  approvedByStaffAt?: string | null;
  signedByDirectorId?: string | null;
  signedByDirectorAt?: string | null;
  signedByCeoId?: string | null;
  signedByCeoAt?: string | null;

  files?: Array<{
    id: string;
    code: string;
    name: string;
    url: string;
    mimeType: string;
    size: number;
    resourceId: string;
    resource: string;
    signedUrl?: string | null;
  }>;

  latestChangeRequestNote?: string | null;
  contractSummary?: string | null;
  pricingBreakdown?: PricingBreakdown | null;
}

export interface PricingBreakdownLineItem {
  code: string;
  /** Computed line total (unitAmount × quantity). */
  amount: number;
  /** Price for a single unit of this charge (e.g. one 20ft container, one ton). */
  unitAmount?: number;
  /** Unit the rate is charged per: PER_CONTAINER | PER_TON | PER_WAGON | PER_KM | FLAT. */
  unit?: string;
  /** How many units this charge applies to (containers, tons, wagons; 1 for FLAT). */
  quantity?: number;
  currency: string;
  description: string;
}

export interface PricingBreakdown {
  currency: string;
  lineItems: PricingBreakdownLineItem[];
  generatedAt: string;
  totalAmount: number;
}

// ── Document clearance (post counter-sign GL workflow) ──────────────────────

export type DocumentReviewStatus = "PENDING" | "APPROVED" | "QUERIED";

/** One row of the clearance document grid (a required doc + its file + review). */
export interface ClearanceDocument {
  fileKey: string;
  label: string;
  required: boolean;
  /** Who supplies this document: the customer, or Global Logistics staff. */
  uploadedBy: "customer" | "gl";
  settingCode: string;
  file: { id: string; name: string; url: string } | null;
  reviewStatus: DocumentReviewStatus | null;
  note: string | null;
}

/** The clearance view for a booking, driving both portals' clearance UI. */
export interface ClearanceView {
  status: string;
  includesCustoms: boolean;
  inputCode: string | null;
  outputCode: string | null;
  documents: ClearanceDocument[];
  /** True once every required customer document is APPROVED (the 100% gate). */
  allApproved: boolean;
}

export interface IInvoice extends BaseEntity {
  bookingId: string;
  invoiceNumber: string;
  amount: number;
  currency: string;
  status: PaymentStatus;
  issuedAt: string;
  dueAt: string;
}

// ── Reference Data (booking form catalog) ──────────────────────────────────────

export interface BookingReferenceYard {
  id: string;
  name: string;
  code: string;
  country: string;
}

export interface BookingReferenceContainerType {
  id: string;
  name: string;
  code: string;
  is_reefer: boolean;
  wagons_per_unit: number;
}

export interface BookingReferenceContainerSizeGroup {
  size: string;
  types: BookingReferenceContainerType[];
}

export interface BookingReferenceService {
  id: string;
  name: string;
  code: string;
  serviceName: string;
  description?: string | null | undefined;
  canBeBookedAlone: boolean;
  includesFirstMile: boolean;
  includesLastMile: boolean;
  includesCustoms: boolean;
  priorityBonusPoints: number;
  isActive: boolean;
  displayOrder: number;
  createdAt: string;
  updatedAt: string;
  deletedAt?: string | null | undefined;
}

export interface BookingReferenceShippingLine {
  id: string;
  name: string;
  code: string;
}

export interface BookingReferenceCargoTypeChild {
  id: string;
  name: string;
  code: string;
  show_free_text_box: boolean;
  /** How this cargo is measured (PER_TON / PER_ITEM); null when unset. */
  unit_of_measure?: CargoUnitOfMeasure | null;
}

export interface BookingReferenceCargoTypeGroup {
  id: string;
  name: string;
  code: string;
  children?: BookingReferenceCargoTypeChild[];
}

export interface BookingReferenceData {
  yard: BookingReferenceYard[];
  containers: BookingReferenceContainerSizeGroup[];
  service: BookingReferenceService[];
  shipping_line: BookingReferenceShippingLine[];
  cargo_type: BookingReferenceCargoTypeGroup[];
}

// ── Train Scheduling (bookable schedules) ──────────────────────────────────────

export interface BookableSchedulesQuery {
  originYardId?: string;
  destinationYardId?: string;
}

export interface AvailableDaysQuery {
  originYardId?: string;
  destinationYardId?: string;
}

/**
 * Day-level booking pool: the EAT calendar days that have at least one OPEN
 * departure on a route. `days` are `yyyy-MM-dd` strings, e.g. `["2026-06-20"]`.
 * No capacity is exposed — customers pick a day, not a train.
 */
export interface AvailableDaysResponse {
  days: string[];
}

export interface BookableScheduleLocomotive {
  id: string;
  code: string;
  name: string | null;
  readiness: string | null;
}

export interface BookableScheduleItem {
  id: string;
  scheduleDate: string;
  trainNumber: string | null;
  routeName: string | null;
  origin: string | null;
  destination: string | null;
  locomotive: BookableScheduleLocomotive | null;
  wagonCount: number;
  totalWeightTons: number;
  totalLengthMeters: number;
  bookingsCount: number;
  freightType: FreightType | "MIXED" | null;
  status: TrainScheduleStatus;
  bookingWindowStatus: ScheduleBookingWindow;
  maxWagons: number;
  remainingWagons: number;
}

// ── DTOs ───────────────────────────────────────────────────────────────────────

export interface CreateBookingContainerDto {
  containerTypeId: string;
  quantity: number;
  vgmPerUnitTons: number;
}

/** A contracted route+quantity line for a GENERAL contract. */
export interface CreateContractRouteDto {
  originYardId: string;
  destinationYardId: string;
  containerTypeId?: string | undefined;
  quantity: number;
}

export interface CreateBookingDto {
  freightShapeValidation?: boolean | undefined;
  reference?: string | undefined;
  isGovernment?: boolean | undefined;
  governmentInstitution?: string | undefined;
  companyId?: string | undefined;
  trainId?: string | undefined;
  trainScheduleId?: string | undefined;
  /** Optional for general contracts — they pick the date per order, not at creation. */
  scheduledDate?: string | undefined;
  /** Defaults to ONE_TIME. GENERAL_CONTRACT creates an umbrella contract. */
  bookingType?: BookingType | undefined;
  contractType: string;
  previousContractId?: string | undefined;
  serviceTypeId: string;
  firstMilePickupAddress?: string | undefined;
  firstMilePickupLat?: number | undefined;
  firstMilePickupLng?: number | undefined;
  lastMileDeliveryAddress?: string | undefined;
  lastMileDeliveryLat?: number | undefined;
  lastMileDeliveryLng?: number | undefined;
  customsClearingEnabled?: boolean | undefined;
  customsClearingAgent?: string | undefined;
  equipmentReturn: string;
  originYardId: string;
  destinationYardId: string;
  tradeDirection: string;
  freightType: string;
  cargoTypeId?: string | undefined;
  cargoFreeText?: string | undefined;
  shippingLineId?: string | undefined;
  cargoTotalWeightVgm: number;
  isHazardous?: boolean | undefined;
  paymentCurrency: string;
  pnrCode?: string | undefined;
  startDate?: string | undefined;
  endDate?: string | undefined;
  financialTerms?: string | undefined;
  containers?: CreateBookingContainerDto[];
  /** GENERAL_CONTRACT only: routes the contract reserves quantity across. */
  routes?: CreateContractRouteDto[];
}

// ── General Contracts & Booking Orders ──────────────────────────────────────────

/**
 * A line of contracted quantity. For CONTAINER contracts there is one line per
 * container type (each its own drawdown pool); for BULK/BREAK_BULK a single line
 * with a null containerTypeId carries the total tons/items.
 */
export interface ContractQuantityLine {
  containerTypeId: string | null;
  containerTypeName?: string | null;
  /** PER_TON / PER_ITEM for bulk-style lines; null for container lines. */
  unitOfMeasure?: CargoUnitOfMeasure | null;
  /** Total contracted units on this line (containers, tons, or items). */
  contractedQuantity: number;
  /** Units already drawn down by non-cancelled orders. */
  orderedQuantity: number;
  /** contractedQuantity − orderedQuantity. */
  remainingQuantity: number;
}

/**
 * Customer-facing view of a general contract (a Booking with
 * bookingType = GENERAL_CONTRACT) and its remaining drawdown pool.
 */
export interface IGeneralContract extends IBooking {
  bookingType: BookingType;
  /** When the contract becomes ACTIVE; when ordering closes. Null until active. */
  expiresAt?: string | null;
  /** Per-line contracted / ordered / remaining quantities. */
  quantityLines: ContractQuantityLine[];
}

export interface CreateBookingOrderLineDto {
  /** Null for bulk/break-bulk; the container type id for container contracts. */
  containerTypeId?: string | null;
  quantity: number;
  /** How much of this line is hazardous (≤ quantity). Defaults to 0. */
  hazardousQuantity?: number;
  /** How much of this line is refrigerated (≤ quantity). Defaults to 0. */
  reeferQuantity?: number;
}

/** Per-route contracted / ordered / remaining pool line (multi-route contracts). */
export interface ContractRouteLine {
  routeLineId: string;
  originYardId: string;
  originYardName?: string | null;
  destinationYardId: string;
  destinationYardName?: string | null;
  containerTypeId?: string | null;
  containerTypeName?: string | null;
  contractedQuantity: number;
  orderedQuantity: number;
  remainingQuantity: number;
  /** Road distance (km) for this route; used to bill road orders. Null for rail-only. */
  km?: number | null;
}

export interface CreateBookingOrderDto {
  /** The general contract (booking) this order draws down from. */
  contractBookingId: string;
  /** For multi-route contracts: the route line being drawn from. */
  routeLineId?: string;
  /** The shipment day the customer wants for this order. */
  scheduledDate: string;
  lines: CreateBookingOrderLineDto[];
}

export interface IBookingOrderLine {
  id: string;
  containerTypeId?: string | null;
  containerTypeName?: string | null;
  quantity: number;
  hazardousQuantity?: number;
  reeferQuantity?: number;
}

export interface IBookingOrder {
  id: string;
  reference: string;
  contractBookingId: string;
  /** The child shipment booking spawned for this order (enters scheduling). */
  bookingId?: string | null;
  bookingReference?: string | null;
  companyId?: string | null;
  scheduledDate: string;
  status: BookingStatus;
  schedulingStatus: SchedulingStatus;
  trainScheduleId?: string | null;
  lines: IBookingOrderLine[];
  createdAt: string;
  updatedAt: string;
}
