import { useMemo } from "react";
import { Badge, Box, Card, Group, ScrollArea, Skeleton, Stack, Text } from "@mantine/core";
import { useQuery } from "@tanstack/react-query";
import { ArrowRight, CalendarClock } from "lucide-react";
import { CountdownTimer } from "@edr/ui-common";

import { api } from "@/services/api";
import type { BatchBoardSchedule } from "@/types/trainScheduling";

/** All window times are communicated in East Africa Time. */
const TZ = "Africa/Addis_Ababa";

function fmtDay(iso: string): string {
  return new Date(iso).toLocaleDateString("en-GB", {
    weekday: "short",
    day: "numeric",
    month: "short",
    timeZone: TZ,
  });
}

function fmtTime(iso: string): string {
  return new Date(iso).toLocaleTimeString("en-GB", {
    hour: "2-digit",
    minute: "2-digit",
    hour12: false,
    timeZone: TZ,
  });
}

function windowLabel(w: BatchBoardSchedule): string {
  if (w.windowOpensAt && w.windowClosesAt) {
    return `${fmtDay(w.windowOpensAt)} · ${fmtTime(w.windowOpensAt)} – ${fmtTime(
      w.windowClosesAt,
    )} EAT`;
  }
  if (w.windowOpensAt) {
    return `Opens ${fmtDay(w.windowOpensAt)} · ${fmtTime(w.windowOpensAt)} EAT`;
  }
  return (w.windowPhase ?? w.bookingWindowStatus).replace(/_/g, " ");
}

/**
 * The countdown for whichever phase the window is currently in, mirroring the
 * customer portal. Phases run pre-window (opens at windowOpensAt) → open (closes
 * at windowClosesAt) → document review (docReviewEndsAt) → payment
 * (paymentPhaseEndsAt). `expiredText` names the NEXT step so a deadline that
 * lapses between the 60s refetches announces what comes next rather than the
 * bare word "Expired". Returns null when no phase is timing down.
 */
function phaseCountdown(
  w: BatchBoardSchedule,
): { label: string; deadline: string; expiredText: string } | null {
  switch (w.windowPhase) {
    case "PRE_WINDOW":
      return w.windowOpensAt
        ? {
            label: "Booking opens in",
            deadline: w.windowOpensAt,
            expiredText: "Booking opening now…",
          }
        : null;
    case "OPEN":
      return w.windowClosesAt
        ? {
            label: "Window closes in",
            deadline: w.windowClosesAt,
            expiredText: "Document review starting…",
          }
        : null;
    case "DOC_REVIEW":
      return w.docReviewEndsAt
        ? {
            label: "Document review ends in",
            deadline: w.docReviewEndsAt,
            expiredText: "Payment starting…",
          }
        : null;
    case "PAYMENT":
      return w.paymentPhaseEndsAt
        ? {
            label: "Payment window ends in",
            deadline: w.paymentPhaseEndsAt,
            expiredText: "Payment window closing…",
          }
        : null;
    default:
      return null;
  }
}

function isOpenNow(w: BatchBoardSchedule): boolean {
  return w.windowPhase === "OPEN" && w.bookingWindowStatus === "OPEN";
}

/** Drop windows whose booking window (or the train itself) has already passed. */
function isPast(w: BatchBoardSchedule): boolean {
  const now = Date.now();
  const closes = w.windowClosesAt ? new Date(w.windowClosesAt).getTime() : null;
  const departs = w.scheduleDate ? new Date(w.scheduleDate).getTime() : null;
  // Still live while in a post-close staff phase (doc review / payment).
  if (w.windowPhase === "DOC_REVIEW" || w.windowPhase === "PAYMENT") return false;
  if (departs != null && departs <= now) return true;
  if (closes != null && closes <= now) return true;
  return false;
}

/**
 * Upcoming / open import booking windows across all train schedules, shown to GL
 * ET on the clearance queue so they can see which lanes are accepting bookings
 * (mirrors the customer's portal "Booking Windows" card). Hidden when nothing is
 * pending. Windows already past close/departure are dropped.
 */
export function GlUpcomingWindowsSection() {
  const { data, isLoading } = useQuery(
    api.trainScheduling.batchBoard.queryOptions({ refetchInterval: 60_000 }),
  );

  const windows = useMemo(() => {
    const rows = (data ?? []).filter(
      (w) => w.windowPhase != null && w.windowPhase !== "DONE" && !isPast(w),
    );
    // Open lanes first, then by opening time.
    return rows.sort((a, b) => {
      const openDiff = Number(isOpenNow(b)) - Number(isOpenNow(a));
      if (openDiff !== 0) return openDiff;
      const at = a.windowOpensAt ? new Date(a.windowOpensAt).getTime() : Infinity;
      const bt = b.windowOpensAt ? new Date(b.windowOpensAt).getTime() : Infinity;
      return at - bt;
    });
  }, [data]);

  if (!isLoading && windows.length === 0) return null;

  return (
    <Card withBorder shadow="sm" radius="lg" p="lg">
      <Group gap={8} mb="md" wrap="nowrap">
        <CalendarClock size={18} />
        <Box>
          <Text fw={700} fz={16}>
            Booking windows
          </Text>
          <Text fz={13} c="dimmed">
            Upcoming and open import booking windows across all lanes (EAT)
          </Text>
        </Box>
      </Group>

      {isLoading ? (
        <Stack gap={8}>
          {[1, 2].map((i) => (
            <Skeleton key={i} height={58} radius="md" />
          ))}
        </Stack>
      ) : (
        <ScrollArea.Autosize mah={340} type="hover">
          <Stack gap={10} pr={4}>
            {windows.map((w) => {
              const open = isOpenNow(w);
              const cd = phaseCountdown(w);
              return (
                <Group
                  key={`${w.scheduleId}-${w.bookingCycleNo}`}
                  justify="space-between"
                  wrap="nowrap"
                  gap={12}
                  p="sm"
                  style={{
                    borderRadius: 12,
                    border: `1px solid ${
                      open
                        ? "var(--mantine-color-edr-green-2)"
                        : "var(--mantine-color-gray-2)"
                    }`,
                    backgroundColor: open
                      ? "var(--mantine-color-edr-green-0)"
                      : undefined,
                  }}
                >
                  <Box style={{ minWidth: 0 }}>
                    <Group gap={6} wrap="nowrap">
                      <Text fz={14} fw={700} truncate>
                        {w.origin ?? "—"}
                      </Text>
                      <ArrowRight size={13} style={{ flexShrink: 0 }} />
                      <Text fz={14} fw={700} truncate>
                        {w.destination ?? "—"}
                      </Text>
                      {w.trainNumber ? (
                        <Text fz={12} c="dimmed" truncate>
                          · {w.trainNumber}
                        </Text>
                      ) : null}
                    </Group>
                    <Text fz={12} c="dimmed" truncate mt={2}>
                      {windowLabel(w)}
                      {w.scheduleDate ? ` · Departs ${fmtDay(w.scheduleDate)}` : ""}
                    </Text>
                    {cd ? (
                      <Box mt={4}>
                        <CountdownTimer
                          deadline={cd.deadline}
                          label={cd.label}
                          expiredText={cd.expiredText}
                          size="xs"
                        />
                      </Box>
                    ) : null}
                  </Box>

                  <Group gap={8} wrap="nowrap" style={{ flexShrink: 0 }}>
                    {w.direction ? (
                      <Badge
                        variant="light"
                        color={w.direction === "IMPORT" ? "blue" : "teal"}
                        radius="sm"
                      >
                        {w.direction === "IMPORT" ? "Import" : "Export"}
                      </Badge>
                    ) : null}
                    <Badge
                      variant={open ? "filled" : "light"}
                      color={
                        open
                          ? "edr-green"
                          : w.windowPhase === "PRE_WINDOW"
                            ? "yellow"
                            : "gray"
                      }
                      radius="sm"
                    >
                      {open
                        ? "Open now"
                        : w.windowPhase === "PRE_WINDOW" && w.windowOpensAt
                          ? `Opens ${fmtTime(w.windowOpensAt)} EAT`
                          : (w.windowPhase ?? w.bookingWindowStatus).replace(
                              /_/g,
                              " ",
                            )}
                    </Badge>
                  </Group>
                </Group>
              );
            })}
          </Stack>
        </ScrollArea.Autosize>
      )}
    </Card>
  );
}
