import { BaseEntity } from '@edr/api-common';
import type { ScheduleTradeDirection } from '@edr/types';
import { Column, Entity, Index, JoinColumn, ManyToOne, OneToMany } from 'typeorm';

import { Yard } from '../../rule-engine/entities/yard.entity';
import { RouteMilestone } from './route-milestone.entity';

export type RouteStatus = 'AVAILABLE' | 'MAINTENANCE' | 'DAMAGED' | 'STOP_WORKING';

@Entity({ schema: 'freight', name: 'routes' })
@Index(['status'])
export class Route extends BaseEntity {
  @Column({ name: 'origin_yard_id', type: 'uuid' })
  originYardId!: string;

  @ManyToOne(() => Yard)
  @JoinColumn({ name: 'origin_yard_id' })
  originYard?: Yard;

  @Column({ name: 'destination_yard_id', type: 'uuid' })
  destinationYardId!: string;

  @ManyToOne(() => Yard)
  @JoinColumn({ name: 'destination_yard_id' })
  destinationYard?: Yard;

  @Column({ name: 'status', type: 'varchar', length: 32, default: 'AVAILABLE' })
  status!: RouteStatus;

  /**
   * Trade direction frozen from the yard countries at create/update
   * (ET→DJ = EXPORT, DJ→ET = IMPORT, same country = DOMESTIC/"Intercity").
   * Consumers (scheduling, booking windows) read this instead of re-deriving.
   */
  @Column({ name: 'direction', type: 'varchar', length: 10 })
  direction!: ScheduleTradeDirection;

  @OneToMany(() => RouteMilestone, (milestone) => milestone.route, { cascade: false })
  milestones?: RouteMilestone[];
}

/**
 * Human-readable route label: yard names, not yard codes — "Addis Ababa → Dire Dawa",
 * not "ADDIS_ABABA → DIRE_DAWA". A yard's display name is its `label`; `code` is the
 * machine identifier and is only a fallback for a yard missing one.
 *
 * When the route's milestones are loaded (with their yards), the label is the FULL
 * ordered corridor — "Addis Ababa → Adama → Dire Dawa" — since milestones already
 * include the origin (first) and destination (last). Without milestones it falls
 * back to origin → destination.
 */
export function formatRouteLabel(route: {
  originYard?: { code?: string; label?: string } | null;
  destinationYard?: { code?: string; label?: string } | null;
  milestones?: Array<{
    sequenceNo: number;
    yard?: { code?: string; label?: string } | null;
  }> | null;
}): string {
  const stops = [...(route.milestones ?? [])]
    .sort((a, b) => a.sequenceNo - b.sequenceNo)
    .map((m) => m.yard?.label ?? m.yard?.code)
    .filter((name): name is string => Boolean(name));
  if (stops.length >= 2) return stops.join(' → ');

  const origin = route.originYard?.label ?? route.originYard?.code ?? 'Origin';
  const dest = route.destinationYard?.label ?? route.destinationYard?.code ?? 'Destination';
  return `${origin} → ${dest}`;
}

export function totalRouteDistanceKm(
  milestones: Array<{ distanceKm?: number | string | null }>,
): number {
  return milestones.reduce((sum, m) => sum + Number(m.distanceKm ?? 0), 0);
}
