import {
  pathStages,
  stageById,
  type Lang,
} from "@/lib/catalog";
import { formatTehran } from "@/lib/format";
import { text } from "@/lib/i18n";

export type StoredEvent = {
  id: number;
  stage_id: string;
  sentence_override: string | null;
  happened_at: string;
};

export type DisplayItem = {
  key: string;
  title: string;
  state: "done" | "current" | "upcoming" | "missed" | "side" | "side-current";
  badge?: string;
  moments: { time: string | null; text: string | null }[];
};

function sentenceOf(event: StoredEvent, lang: Lang) {
  if (event.sentence_override) return event.sentence_override;
  return stageById(event.stage_id)?.sentence[lang] ?? "";
}

export function sortEvents(events: StoredEvent[]) {
  return [...events].sort((a, b) => {
    const byTime = a.happened_at.localeCompare(b.happened_at);
    return byTime || a.id - b.id;
  });
}

export function currentStageId(events: StoredEvent[]) {
  const sorted = sortEvents(events);
  return sorted.length ? sorted[sorted.length - 1].stage_id : "";
}

export function nextStageId(events: StoredEvent[]) {
  const sorted = sortEvents(events);
  const reached = sorted
    .map((event) => stageById(event.stage_id))
    .filter((stage) => stage?.kind === "path")
    .map((stage) => stage!.order);
  const current = reached.length ? Math.max(...reached) : 0;
  return pathStages().find((stage) => stage.order === current + 1)?.id ?? "journey-complete";
}

export function buildTrack(events: StoredEvent[], lang: Lang, titleLang: Lang = lang): DisplayItem[] {
  const copy = text(lang);
  const sorted = sortEvents(events);
  const latest = sorted[sorted.length - 1];
  const latestIsSide = latest ? stageById(latest.stage_id)?.kind === "side" : false;
  const reachedOrders = sorted
    .map((event) => stageById(event.stage_id))
    .filter((stage) => stage?.kind === "path")
    .map((stage) => stage!.order);
  const currentOrder = reachedOrders.length ? Math.max(...reachedOrders) : 0;
  const path = pathStages();

  const sideByAnchor = new Map<number, StoredEvent[]>();
  for (const event of sorted) {
    const stage = stageById(event.stage_id);
    if (!stage || stage.kind !== "side") continue;
    let anchor = 1;
    for (const item of path) {
      const before = sorted.some(
        (row) => row.stage_id === item.id && row.happened_at <= event.happened_at,
      );
      if (before) anchor = item.order;
    }
    const list = sideByAnchor.get(anchor) ?? [];
    list.push(event);
    sideByAnchor.set(anchor, list);
  }

  const items: DisplayItem[] = [];
  for (const stage of path) {
    const stageEvents = sorted.filter((event) => event.stage_id === stage.id);
    let state: DisplayItem["state"];
    if (stage.order > currentOrder) state = "upcoming";
    else if (stage.order === currentOrder && !latestIsSide) state = "current";
    else if (stageEvents.length === 0) state = "missed";
    else state = "done";

    const moments =
      state === "upcoming"
        ? [{ time: null, text: copy.upcoming }]
        : state === "missed"
          ? [{ time: null, text: copy.missed }]
          : stageEvents.map((event) => ({
              time: formatTehran(event.happened_at, lang),
              text: sentenceOf(event, lang),
            }));

    items.push({
      key: stage.id,
      title: stage.title[titleLang],
      state,
      badge: state === "current" ? copy.current : undefined,
      moments,
    });

    for (const event of sideByAnchor.get(stage.order) ?? []) {
      const isCurrent = latest?.id === event.id;
      const side = stageById(event.stage_id);
      items.push({
        key: `side-${event.id}`,
        title: side?.title[titleLang] ?? event.stage_id,
        state: isCurrent ? "side-current" : "side",
        badge: isCurrent ? copy.current : undefined,
        moments: [
          {
            time: formatTehran(event.happened_at, lang),
            text: sentenceOf(event, lang),
          },
        ],
      });
    }
  }
  return items;
}
