import { Freight } from "@edr/types";

const { BookingStatus, TrainScheduleStatus } = Freight;

export function isArrived(
  status?: Freight.TrainScheduleStatus | null,
): boolean {
  return status === TrainScheduleStatus.Arrived;
}

export function isDispatched(
  status?: Freight.TrainScheduleStatus | null,
): boolean {
  return status === TrainScheduleStatus.Dispatched;
}

/** Human label for the schedule status, from the rider's point of view. */
export function shipmentStatusLabel(
  status?: Freight.TrainScheduleStatus | null,
  currentSequenceNo = -1,
): string {
  switch (status) {
    case TrainScheduleStatus.Arrived:
      return "Arrived";
    case TrainScheduleStatus.Dispatched:
      return currentSequenceNo <= 0 ? "Departed" : "In transit";
    case TrainScheduleStatus.Scheduled:
      return "Scheduled";
    case TrainScheduleStatus.Cancelled:
      return "Cancelled";
    case TrainScheduleStatus.Draft:
      return "Preparing";
    default:
      return "Not dispatched";
  }
}

/**
 * 0–100 progress across the corridor, derived from how many stations the train
 * has reached. Arrived → 100. Not departed → 0.
 */
export function corridorProgress(
  stationCount: number,
  currentSequenceNo: number,
  arrived: boolean,
): number {
  if (arrived) return 100;
  if (stationCount <= 1 || currentSequenceNo < 0) return 0;
  const lastSeq = stationCount - 1;
  return Math.round((Math.min(currentSequenceNo, lastSeq) / lastSeq) * 100);
}

// ── Per-booking journey (segment corridor bookings) ───────────────────────────

/**
 * The booking's own journey state, independent of the train: a sub-corridor
 * booking is loaded at its own origin yard and unloaded (ARRIVED) at its own
 * destination yard while the train may keep going. `null` means the booking
 * has no per-booking journey data yet (legacy bookings) — callers fall back
 * to the train-schedule status.
 */
export type BookingJourneyState = "arrived" | "in-transit" | null;

export function bookingJourneyState(
  t: Freight.IBookingTracking,
): BookingJourneyState {
  const status = t.bookingStatus ?? null;
  if (
    t.arrivedAt ||
    status === BookingStatus.Arrived ||
    status === BookingStatus.Completed ||
    status === BookingStatus.Delivered
  ) {
    return "arrived";
  }
  if (t.loadedAt) return "in-transit";
  return null;
}

/**
 * Header pill label. Prefers the booking's own journey (loaded/unloaded at its
 * own yards) and falls back to the train-schedule wording for legacy bookings
 * without per-booking journey data.
 */
export function bookingShipmentStatusLabel(
  journey: BookingJourneyState,
  scheduleStatus: Freight.TrainScheduleStatus | null,
  currentSequenceNo: number,
): string {
  if (journey === "arrived") return "Arrived";
  if (journey === "in-transit") return "In transit";
  return shipmentStatusLabel(scheduleStatus, currentSequenceNo);
}

/**
 * Index range [start..end] of the booking's own leg on the corridor, matched
 * by yardId. Null when the booking rides the full corridor (no leg data) or
 * either endpoint isn't a station on this train's route.
 */
export function bookingLegRange(
  stations: Freight.ITrackingStation[],
  originYardId?: string | null,
  destinationYardId?: string | null,
): { start: number; end: number } | null {
  if (!originYardId || !destinationYardId) return null;
  const start = stations.findIndex((s) => s.yardId === originYardId);
  const end = stations.findIndex((s) => s.yardId === destinationYardId);
  if (start < 0 || end < 0) return null;
  return start <= end ? { start, end } : { start: end, end: start };
}

/** Caption for a checkpoint kind. */
export function checkpointKindLabel(kind: Freight.TrainCheckpointKind): string {
  switch (kind) {
    case Freight.TrainCheckpointKind.Departed:
      return "Departed";
    case Freight.TrainCheckpointKind.Arrived:
      return "Arrived";
    case Freight.TrainCheckpointKind.Passed:
    default:
      return "Passed";
  }
}
