import { api as apiClient } from "../auth/http";

// ---------------------------------------------------------------------------
// Types — mirror the freight API's train-builder responses
// ---------------------------------------------------------------------------

export type BuiltTrainStatus =
  | "AVAILABLE"
  | "SCHEDULED"
  | "IN_SERVICE"
  | "UNDER_MAINTENANCE"
  | "OUT_OF_SERVICE"
  | "DEACTIVATED";

export interface YardRefLite {
  id: string;
  code: string;
  label: string;
}

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

/** The one active (DRAFT/SCHEDULED/DISPATCHED) schedule surfaced per built train. */
export interface ActiveScheduleRef {
  id: string;
  status: string;
  reference: string | null;
  direction: TradeDirection | null;
  trainNumber: string | null;
}

export interface BuiltTrainSummary {
  id: string;
  code: string;
  trainName: string | null;
  status: BuiltTrainStatus;
  /** Fixed IMPORT (even) run number typed at build time. */
  importTrainNumber: string | null;
  /** Fixed EXPORT (odd) run number typed at build time. */
  exportTrainNumber: string | null;
  activeSchedule: ActiveScheduleRef | null;
  createdAt: string;
  currentYard: YardRefLite | null;
  locomotives: Array<{ id: string; code: string; name: string | null }>;
  wagonCount: number;
  totalTareTons: number;
  totalLengthMeters: number;
  maxPullWeightTons: number;
}

export interface TrainCompositionLocomotive {
  id: string;
  code: string;
  name: string | null;
  locomotiveType: "DIESEL" | "ELECTRIC";
  status: string;
  sequenceNo: number;
  role: "LEAD" | "ASSIST";
  currentYardId: string | null;
  currentYard: YardRefLite | null;
  maxPullWeightTons: number;
  maxTrainLengthMeters: number;
}

export interface TrainCompositionWagon {
  id: string;
  wagonNumber: string;
  sequenceNumber: number | null;
  status: string;
  wagonType: {
    id: string;
    code: string;
    name: string;
    capacityTons: number;
    tareWeightTons: number;
    lengthMeters: number;
  } | null;
}

export interface TrainCompositionTotals {
  wagonCount: number;
  totalTareTons: number;
  /** Informational only — building never checks against full capacity. */
  totalCapacityTons: number;
  totalLengthMeters: number;
  maxPullWeightTons: number;
  maxTrainLengthMeters: number;
  /** Cargo the locomotives can still haul once pulling the empty consist. */
  payloadCapacityTons: number;
  /** Share of the haul limit consumed by the empty wagons alone. */
  tareUtilizationPct: number | null;
  lengthUtilizationPct: number | null;
}

export interface TrainComposition {
  id: string;
  code: string;
  trainName: string | null;
  status: BuiltTrainStatus;
  importTrainNumber: string | null;
  exportTrainNumber: string | null;
  notes: string | null;
  createdAt: string;
  currentYard: YardRefLite | null;
  locomotives: TrainCompositionLocomotive[];
  wagons: TrainCompositionWagon[];
  totals: TrainCompositionTotals;
  activeSchedules: ActiveScheduleRef[];
  editable: boolean;
}

export interface BuiltTrainListFilters {
  page?: number;
  pageSize?: number;
  search?: string;
  status?: BuiltTrainStatus;
  currentYardId?: string;
  sortBy?: "code" | "trainName" | "status" | "createdAt";
  sortOrder?: "ASC" | "DESC";
}

export interface BuiltTrainListResponse {
  items: BuiltTrainSummary[];
  meta: {
    total: number;
    page: number;
    pageSize: number;
    totalPages: number;
  };
}

export interface BuildTrainPayload {
  /** EXPORT run number — odd, unique across trains (e.g. 8001). */
  exportTrainNumber: string;
  /** IMPORT run number — even, unique across trains (e.g. 8002). */
  importTrainNumber: string;
  currentYardId: string;
  locomotiveIds: string[];
  wagonIds?: string[];
  trainName?: string;
  notes?: string;
}

/** Run numbers already claimed by existing (non-deleted) trains. */
export interface UsedTrainNumbers {
  importTrainNumbers: string[];
  exportTrainNumbers: string[];
}

/** Edit a built train's display identity; omitted fields keep their value. */
export interface UpdateTrainDetailsPayload {
  /** Empty string clears the name. */
  trainName?: string;
  importTrainNumber?: string;
  exportTrainNumber?: string;
}

/** Built train annotated for the schedule-creation picker. */
export interface AvailableTrain {
  id: string;
  code: string;
  trainName: string | null;
  status: BuiltTrainStatus;
  importTrainNumber: string | null;
  exportTrainNumber: string | null;
  currentYardId: string | null;
  currentYard: YardRefLite | null;
  locomotives: Array<{ id: string; code: string; name: string | null }>;
  wagonCount: number;
  totalTareTons: number;
  totalLengthMeters: number;
  maxPullWeightTons: number;
  atOriginYard: boolean;
  futureScheduleCount: number;
}

// ---------------------------------------------------------------------------
// Service
// ---------------------------------------------------------------------------

const BASE = "/train-builder";

const toQuery = (filters: BuiltTrainListFilters = {}) => {
  const params = new URLSearchParams();
  Object.entries(filters).forEach(([key, value]) => {
    if (value !== undefined && value !== null && value !== "") {
      params.set(key, String(value));
    }
  });
  const qs = params.toString();
  return qs ? `?${qs}` : "";
};

// ---------------------------------------------------------------------------
// Schedule consist adjustment (train-bound schedules)
// ---------------------------------------------------------------------------

export interface ConsistWagonRef {
  id: string;
  wagonNumber: string;
  sequenceNumber: number | null;
  wagonType: {
    id: string;
    code: string;
    tareWeightTons: number;
    capacityTons: number;
    lengthMeters: number;
  } | null;
}

export interface ScheduleConsist {
  schedule: { id: string; reference: string | null; status: string };
  train: {
    id: string;
    code: string;
    trainName: string | null;
    currentYardId: string | null;
  };
  limits: {
    maxPullWeightTons: number;
    overageToleranceTons: number;
    pullCapTons: number;
    maxTrainLengthMeters: number;
    overageToleranceMeters: number;
    lengthCapMeters: number;
  };
  totals: {
    wagonCount: number;
    cargoTons: number;
    consistTareTons: number;
    grossTons: number;
    consistLengthMeters: number;
  };
  wagons: Array<ConsistWagonRef & { loaded: boolean; removable: boolean }>;
  addableWagons: ConsistWagonRef[];
  adjustments: Array<{
    id: string;
    action: "ADD" | "REMOVE";
    wagonId: string;
    wagonNumber: string;
    adjustedByUserId: string | null;
    occurredAt: string;
  }>;
  editable: boolean;
  /**
   * Wagon-slot picture of the schedule: the consist IS the booking capacity
   * (weight/length only bind while building the consist), so the dialog can
   * project FULL / reopen / over-allocation live. Null on legacy schedules.
   */
  scheduleCapacity: {
    maxWagons: number;
    allocatedWagons: number;
    remainingSlots: number;
    overAllocatedBy: number;
    bookingWindowStatus: string | null;
  } | null;
}

export interface AdjustConsistPayload {
  addWagonIds?: string[];
  removeWagonIds?: string[];
}

/** Adjust response: fresh consist + schedule-impact warnings to surface. */
export type AdjustConsistResult = ScheduleConsist & { warnings: string[] };

export const trainBuilderService = {
  list: (filters: BuiltTrainListFilters = {}) =>
    apiClient.get<BuiltTrainListResponse>(`${BASE}${toQuery(filters)}`),
  getComposition: (id: string) => apiClient.get<TrainComposition>(`${BASE}/${id}`),
  /** Import/export run numbers already claimed by existing trains. */
  usedTrainNumbers: () => apiClient.get<UsedTrainNumbers>(`${BASE}/used-train-numbers`),
  build: (payload: BuildTrainPayload) => apiClient.post<TrainComposition>(BASE, payload),
  setLocomotives: (id: string, locomotiveIds: string[]) =>
    apiClient.put<TrainComposition>(`${BASE}/${id}/locomotives`, { locomotiveIds }),
  /** Edit the train's name and fixed import/export run numbers. */
  updateDetails: (id: string, payload: UpdateTrainDetailsPayload) =>
    apiClient.patch<TrainComposition>(`${BASE}/${id}/details`, payload),
  /** Relocate the train — coupled locomotives and wagons move with it. */
  setYard: (id: string, currentYardId: string) =>
    apiClient.patch<TrainComposition>(`${BASE}/${id}/yard`, { currentYardId }),
  assignWagons: (id: string, wagonIds: string[]) =>
    apiClient.post<TrainComposition>(`${BASE}/${id}/wagons`, { wagonIds }),
  removeWagon: (id: string, wagonId: string) =>
    apiClient.delete<TrainComposition>(`${BASE}/${id}/wagons/${wagonId}`),
  /** Detach a wagon and move it to MAINTENANCE status. */
  sendWagonToMaintenance: (id: string, wagonId: string) =>
    apiClient.post<TrainComposition>(`${BASE}/${id}/wagons/${wagonId}/maintenance`),
  reorderWagons: (id: string, wagonIds: string[]) =>
    apiClient.post<TrainComposition>(`${BASE}/${id}/reorder-wagons`, { wagonIds }),
  /** Park the train indefinitely — only allowed with no active schedule. */
  deactivate: (id: string) =>
    apiClient.post<TrainComposition>(`${BASE}/${id}/deactivate`),
  /** Bring a DEACTIVATED train back to AVAILABLE. */
  activate: (id: string) => apiClient.post<TrainComposition>(`${BASE}/${id}/activate`),
  disband: (id: string) => apiClient.delete<void>(`${BASE}/${id}`),
  /** Built trains schedulable on a route (train-scheduling picker). */
  availableTrains: (routeId: string) =>
    apiClient.get<AvailableTrain[]>(`/train-scheduling/available-trains`, {
      params: { routeId },
    }),
  /** Consist snapshot for a train-bound schedule (adjust-consist UI). */
  scheduleConsist: (scheduleId: string) =>
    apiClient.get<ScheduleConsist>(`/train-scheduling/schedules/${scheduleId}/consist`),
  /** Permanently trim/add wagons on the schedule's built train. */
  adjustConsist: (scheduleId: string, payload: AdjustConsistPayload) =>
    apiClient.post<AdjustConsistResult>(
      `/train-scheduling/schedules/${scheduleId}/adjust-consist`,
      payload,
    ),
};
