import type { Freight, PaginatedResponse } from "@edr/types";

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

export interface Wagon {
  id: string;
  wagonNumber: string;
  wagonTypeId: string;
  trainId: string | null;
  sequenceNumber: number | null;
  currentLocationYardId: string | null;
  currentLocationYard?: {
    id: string;
    code: string;
    label: string;
    country?: string;
  } | null;
  /** Owns this wagon's spec — tare, capacity, length are read from here, never off the wagon. */
  wagonType?: {
    id: string;
    code: string;
    name: string;
    supportedLoadTypes?: string[];
    tareWeightTons?: number;
    capacityTons?: number;
    lengthMeters?: number;
  } | null;
  status: Freight.WagonStatus;
  currentYardId: string | null;
  currentYard?: { id: string; label?: string; code?: string } | null;
  /** Odd EXPORT run (Ethiopia → Djibouti); null when the wagon is not on a run. */
  exportTrainNumber?: string | null;
  /** Even IMPORT run (Djibouti → Ethiopia); always the export run + 1. */
  importTrainNumber?: string | null;
  notes?: string;
}

export interface WagonListFilters {
  search?: string;
  status?: Freight.WagonStatus;
  currentYardId?: string;
  wagonTypeId?: string;
  trainId?: string;
  /** Run number — matches a wagon whose export OR import run equals it. */
  trainNumber?: string;
}

/**
 * One row of the wagon_movements ledger: every physical relocation between
 * yards — a booking's loaded leg, an empty reposition ride, or a manual staff
 * correction. Returned newest first by the API.
 */
export interface WagonMovementRecord {
  id: string;
  wagonId: string;
  fromYardId: string | null;
  toYardId: string;
  fromYard?: { id?: string; label?: string; code?: string } | null;
  toYard?: { id?: string; label?: string; code?: string } | null;
  trainScheduleId: string | null;
  bookingId: string | null;
  kind: Freight.WagonMovementKind;
  movedByUserId: string | null;
  /** The transfer request this move fulfilled, when one drove it. */
  transferRequestId: string | null;
  occurredAt: string;
  note: string | null;
  createdAt: string;
  wagon?: { id: string; wagonNumber?: string } | null;
}

export const wagonService = {
  getAll: (filters: WagonListFilters = {}) => {
    const params = new URLSearchParams();
    if (filters.search?.trim()) params.set('search', filters.search.trim());
    if (filters.status) params.set('status', filters.status);
    if (filters.currentYardId) params.set('currentYardId', filters.currentYardId);
    if (filters.wagonTypeId) params.set('wagonTypeId', filters.wagonTypeId);
    if (filters.trainId) params.set('trainId', filters.trainId);
    if (filters.trainNumber) params.set('trainNumber', filters.trainNumber);
    const qs = params.toString();
    return apiClient.get<Wagon[]>(`/wagons${qs ? `?${qs}` : ''}`);
  },
  getById: (id: string) => apiClient.get<Wagon>(`/wagons/${id}`),
  getMovements: (id: string) =>
    apiClient.get<WagonMovementRecord[]>(`/wagons/${id}/movements`),
  getByTrain: (trainId: string) => apiClient.get<Wagon[]>(`/wagons?trainId=${trainId}`),
  assignToTrain: (wagonId: string, trainId: string, sequenceNumber?: number) =>
    apiClient.post(`/wagons/${wagonId}/assign-train`, { trainId, sequenceNumber }),
  unassign: (wagonId: string) => apiClient.post(`/wagons/${wagonId}/unassign-train`),
  create: (data: Partial<Wagon>) => apiClient.post('/wagons', data),
  update: (id: string, data: Partial<Wagon>) => apiClient.patch(`/wagons/${id}`, data),
  delete: (id: string) => apiClient.delete(`/wagons/${id}`),
  /** Relocate many wagons to one yard in a single call (writes movement ledger). */
  bulkTransfer: (wagonIds: string[], toYardId: string) =>
    apiClient.post<{ moved: number }>('/wagons/bulk-transfer', { wagonIds, toYardId }),
  /** Set the same status on many wagons in a single call. */
  bulkSetStatus: (wagonIds: string[], status: Freight.WagonStatus) =>
    apiClient.post<{ updated: number }>('/wagons/bulk-status', { wagonIds, status }),
};

/**
 * A two-person wagon-transfer request: a requester asks for N wagons of a type
 * to move between yards (count only); OCC hand-picks the wagons and fulfils it.
 */
export interface WagonTransferRequest {
  id: string;
  fromYardId: string;
  toYardId: string;
  wagonTypeId: string;
  quantity: number;
  /** How many have actually moved so far — OCC delivers in instalments. */
  fulfilledQuantity: number;
  status: Freight.WagonTransferRequestStatus;
  requestedByUserId: string | null;
  fulfilledByUserId: string | null;
  /** When the LAST instalment ran, not necessarily the full count. */
  fulfilledAt: string | null;
  closedShortAt?: string | null;
  closedShortByUserId?: string | null;
  /** Why the wagons are needed — required for new requests, shown on the queue. */
  reason?: string | null;
  note: string | null;
  fromYard?: { id: string; label?: string; code?: string } | null;
  toYard?: { id: string; label?: string; code?: string } | null;
  wagonType?: { id: string; code?: string; name?: string } | null;
  createdAt: string;
}

export interface CreateTransferRequestPayload {
  fromYardId: string;
  toYardId: string;
  wagonTypeId: string;
  quantity: number;
  /** Mandatory: why the wagons are needed. */
  reason: string;
  note?: string;
}

/** Bulk accept-and-execute result: what ran, what stayed open and why. */
export interface BulkFulfillResult {
  fulfilled: WagonTransferRequest[];
  skipped: Array<{ id: string; reason: string }>;
}

/** Per-user activity: requests filed/fulfilled + the wagons physically moved. */
export interface TransferHistory {
  requests: WagonTransferRequest[];
  movements: WagonMovementRecord[];
  meta: {
    page: number;
    pageSize: number;
    requestsTotal: number;
    movementsTotal: number;
    totalPages: number;
  };
}

/** Desk list filters — `status` may be a comma-separated set ("open" tab). */
export interface TransferRequestListFilter {
  status?: string;
  fromYardId?: string;
  toYardId?: string;
  wagonTypeId?: string;
  search?: string;
  page?: number;
  pageSize?: number;
}

const listQuery = (filter: TransferRequestListFilter = {}): string => {
  const params = new URLSearchParams();
  for (const [key, value] of Object.entries(filter)) {
    if (value !== undefined && value !== null && value !== '') {
      params.set(key, String(value));
    }
  }
  const qs = params.toString();
  return qs ? `?${qs}` : '';
};

export const wagonTransferRequestService = {
  list: (filter: TransferRequestListFilter = {}) =>
    apiClient.get<PaginatedResponse<WagonTransferRequest>>(
      `/wagon-transfer-requests${listQuery(filter)}`,
    ),
  /** The caller's own history (both roles: requests they filed and fulfilled). */
  myHistory: (page = 1, pageSize = 20) =>
    apiClient.get<TransferHistory>(
      `/wagon-transfer-requests/history?page=${page}&pageSize=${pageSize}`,
    ),
  /** Admin: any/all staff's history (optional userId filter). */
  allHistory: (userId?: string, page = 1, pageSize = 20) =>
    apiClient.get<TransferHistory>(
      `/wagon-transfer-requests/history/all?page=${page}&pageSize=${pageSize}` +
        `${userId ? `&userId=${userId}` : ''}`,
    ),
  getById: (id: string) =>
    apiClient.get<WagonTransferRequest>(`/wagon-transfer-requests/${id}`),
  create: (data: CreateTransferRequestPayload) =>
    apiClient.post<WagonTransferRequest>('/wagon-transfer-requests', data),
  /** OCC: accept-and-execute a subset of pending requests (auto-picked wagons). */
  bulkFulfill: (requestIds: string[]) =>
    apiClient.post<BulkFulfillResult>('/wagon-transfer-requests/bulk-fulfill', {
      requestIds,
    }),
  /** OCC: execute the transfer with the hand-picked wagons. */
  fulfill: (id: string, wagonIds: string[]) =>
    apiClient.post<WagonTransferRequest>(
      `/wagon-transfer-requests/${id}/fulfill`,
      { wagonIds },
    ),
  cancel: (id: string) =>
    apiClient.post<WagonTransferRequest>(
      `/wagon-transfer-requests/${id}/cancel`,
    ),
  /** OCC: end the request short — the source yard has no more to give. */
  closeShort: (id: string, note?: string) =>
    apiClient.post<WagonTransferRequest>(
      `/wagon-transfer-requests/${id}/close-short`,
      { note },
    ),
};
