import { ActionIcon, Box, Group, Skeleton, Stack, Text } from "@mantine/core";
import { Fragment, memo, useMemo, useState } from "react";
import {
  ArrowRight,
  CalendarClock,
  ChevronLeft,
  ChevronRight,
} from "lucide-react";
import { CountdownTimer, bookingWindowUiState } from "@edr/ui-common";
import type { MyBookingWindow } from "@/services/bookings.service";
import { windowRouteStops } from "@/pages/contracts/booking-window";
import { Card } from "./Card";

const INK = "#10202F";
const MUTED = "#6B7C8E";
const BORDER = "#E6ECF2";

/** 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,
  });
}

/** "Thu, 10 Jul · 08:00 – 11:00 EAT" (or a phase label when times are unset). */
function windowLabel(w: MyBookingWindow): 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 the window's UI state (shared with the status badge via
 * `bookingWindowUiState`, so the two can never contradict — a FULL train shows
 * no ticking "closes in" under a non-open badge).
 *
 * `label` describes the deadline being counted down to; `expiredText` names the
 * NEXT step so that when a deadline lapses between the 60s refetches the row
 * announces what comes next ("Booking opening now…", "Review starting…") rather
 * than the bare word "Expired". Returns null when no phase is timing down.
 */
const COUNTDOWN_TEXT: Partial<
  Record<
    ReturnType<typeof bookingWindowUiState>["kind"],
    { label: string; expiredText: string }
  >
> = {
  PRE_WINDOW: { label: "Booking opens in", expiredText: "Booking opening now…" },
  OPEN: { label: "Window closes in", expiredText: "Document review starting…" },
  DOC_REVIEW: { label: "Document review ends in", expiredText: "Payment starting…" },
  PAYMENT: { label: "Payment due in", expiredText: "Payment window closing…" },
};

function phaseCountdown(
  w: MyBookingWindow,
): { label: string; deadline: string; expiredText: string } | null {
  const state = bookingWindowUiState(w);
  const text = COUNTDOWN_TEXT[state.kind];
  if (!state.countdownTo || !text) return null;
  return { ...text, deadline: state.countdownTo };
}

function Pill({
  children,
  bg,
  color,
  border,
}: {
  children: React.ReactNode;
  bg: string;
  color: string;
  border?: string;
}) {
  return (
    <Box
      component="span"
      style={{
        display: "inline-flex",
        alignItems: "center",
        gap: 4,
        borderRadius: 999,
        padding: "4px 10px",
        fontSize: 11,
        fontWeight: 700,
        whiteSpace: "nowrap",
        backgroundColor: bg,
        color,
        border: border ? `1px solid ${border}` : undefined,
      }}
    >
      {children}
    </Box>
  );
}

function DirectionBadge({ direction }: { direction: MyBookingWindow["direction"] }) {
  if (!direction) return null;
  const isImport = direction === "IMPORT";
  return (
    <Pill
      bg={isImport ? "#EAF1FB" : "#ECF6F1"}
      color={isImport ? "#2E5B96" : "#0A6F4D"}
    >
      {isImport ? "Import" : "Export"}
    </Pill>
  );
}

function StatusBadge({ window: w }: { window: MyBookingWindow }) {
  const state = bookingWindowUiState(w);
  switch (state.kind) {
    case "OPEN":
      return (
        <Pill bg="#ECF6F1" color="#0A6F4D" border="#CDEBDD">
          Open now
        </Pill>
      );
    case "FULL":
      return (
        <Pill bg="#FDECEA" color="#B3261E" border="#F6C9C4">
          Train full
        </Pill>
      );
    case "PRE_WINDOW":
      if (w.windowOpensAt) {
        return (
          <Pill bg="#FEF6E6" color="#B07D14">
            Opens at {fmtTime(w.windowOpensAt)} EAT
          </Pill>
        );
      }
      break;
    case "DOC_REVIEW":
      return (
        <Pill bg="#EAF1FB" color="#2E5B96">
          Document review
        </Pill>
      );
    case "PAYMENT":
      return (
        <Pill bg="#EAF1FB" color="#2E5B96">
          Payment window
        </Pill>
      );
    case "CLOSED":
      return (
        <Pill bg="#F1F5F9" color={MUTED}>
          Closed
        </Pill>
      );
  }
  return (
    <Pill bg="#F1F5F9" color={MUTED}>
      Upcoming
    </Pill>
  );
}

interface UpcomingWindowsSectionProps {
  windows: MyBookingWindow[];
  isLoading: boolean;
}

/**
 * All announced upcoming/open booking windows, shown to every customer
 * regardless of whether they hold a contract on the lane. Import trains open a
 * window on one booking day; export trains open 24h before departure. Rows on a
 * lane the customer has an active contract for carry a "Book now" action;
 * others route to the contract list. Hidden entirely when nothing is announced.
 */
/** Rows shown per carousel page. */
const PER_PAGE = 3;

export const UpcomingWindowsSection = memo(function UpcomingWindowsSection({
  windows,
  isLoading,
}: UpcomingWindowsSectionProps) {
  const [page, setPage] = useState(0);

  // Order by the train's dispatch (departure) date, nearest first. Open-now
  // breaks ties on the same departure so an actionable lane leads.
  const sorted = useMemo(
    () =>
      [...windows].sort((a, b) => {
        const da = a.departureDate ? new Date(a.departureDate).getTime() : Infinity;
        const db = b.departureDate ? new Date(b.departureDate).getTime() : Infinity;
        if (da !== db) return da - db;
        return Number(b.isOpenNow) - Number(a.isOpenNow);
      }),
    [windows],
  );

  const pageCount = Math.max(1, Math.ceil(sorted.length / PER_PAGE));
  const safePage = Math.min(page, pageCount - 1);
  const visible = sorted.slice(safePage * PER_PAGE, safePage * PER_PAGE + PER_PAGE);

  // Nothing upcoming — keep the dashboard uncluttered.
  if (!isLoading && windows.length === 0) return null;

  return (
    <Card padding={28}>
      <Group justify="space-between" align="center" mb={18} wrap="nowrap">
        <Box>
          <Text fz={19} fw={800} c="edr-text">
            Booking Windows
          </Text>
          <Text fz={13} c="edr-muted">
            Upcoming and open booking windows across all lanes
          </Text>
        </Box>

        {pageCount > 1 ? (
          <Group gap={8} wrap="nowrap">
            <ActionIcon
              variant="default"
              radius="xl"
              size="lg"
              aria-label="Previous windows"
              disabled={safePage <= 0}
              onClick={() => setPage((p) => Math.max(0, p - 1))}
            >
              <ChevronLeft size={18} />
            </ActionIcon>
            <Group gap={5} wrap="nowrap">
              {Array.from({ length: pageCount }, (_, i) => (
                <Box
                  key={i}
                  onClick={() => setPage(i)}
                  style={{
                    width: i === safePage ? 18 : 7,
                    height: 7,
                    borderRadius: 999,
                    cursor: "pointer",
                    background: i === safePage ? "#0A6F4D" : "#D8E2EB",
                    transition: "width 200ms ease, background 200ms ease",
                  }}
                />
              ))}
            </Group>
            <ActionIcon
              variant="default"
              radius="xl"
              size="lg"
              aria-label="Next windows"
              disabled={safePage >= pageCount - 1}
              onClick={() => setPage((p) => Math.min(pageCount - 1, p + 1))}
            >
              <ChevronRight size={18} />
            </ActionIcon>
          </Group>
        ) : null}
      </Group>

      {isLoading ? (
        <Stack gap={6}>
          {[1, 2, 3].map((i) => (
            <Skeleton key={i} height={60} radius="md" />
          ))}
        </Stack>
      ) : (
        <Stack gap={10} key={safePage}>
          {visible.map((w) => (
            <Group
              key={`${w.scheduleId}-${w.bookingCycleNo}`}
              justify="space-between"
              wrap="nowrap"
              gap={12}
              p="sm"
              style={{
                borderRadius: 12,
                border: `1px solid ${w.isOpenNow ? "#CDEBDD" : BORDER}`,
                backgroundColor: w.isOpenNow ? "#F4FBF7" : undefined,
              }}
            >
              <Box style={{ minWidth: 0 }}>
                <Group gap={6} wrap="wrap">
                  {windowRouteStops(w).map((stop, i) => (
                    <Fragment key={i}>
                      {i > 0 ? (
                        <ArrowRight
                          size={13}
                          color={MUTED}
                          style={{ flexShrink: 0 }}
                        />
                      ) : null}
                      <Text fz={14} fw={700} style={{ color: INK }}>
                        {stop}
                      </Text>
                    </Fragment>
                  ))}
                  {w.reference && (
                    <Text
                      fz={11}
                      fw={600}
                      style={{
                        color: MUTED,
                        flexShrink: 0,
                        fontVariantNumeric: "tabular-nums",
                      }}
                    >
                      {w.reference}
                    </Text>
                  )}
                </Group>
                <Group gap={5} wrap="nowrap" mt={2}>
                  <CalendarClock size={12} color={MUTED} style={{ flexShrink: 0 }} />
                  <Text fz={12} style={{ color: MUTED }} truncate>
                    {windowLabel(w)} · Departs {fmtDay(w.departureDate)}
                  </Text>
                </Group>
                {(() => {
                  const cd = phaseCountdown(w);
                  return cd ? (
                    <Box mt={4}>
                      <CountdownTimer
                        deadline={cd.deadline}
                        label={cd.label}
                        expiredText={cd.expiredText}
                        size="xs"
                      />
                    </Box>
                  ) : null;
                })()}
              </Box>

              {/* Windows are informational here — booking is done from the
                  contract page while a window is open, not via a home CTA. */}
              <Group gap={8} wrap="nowrap" style={{ flexShrink: 0 }}>
                <DirectionBadge direction={w.direction} />
                <StatusBadge window={w} />
              </Group>
            </Group>
          ))}
        </Stack>
      )}
    </Card>
  );
});
