import { useMemo, useState } from "react";
import { useNavigate } from "react-router-dom";
import {
  ActionIcon,
  Alert,
  Box,
  Button,
  Card,
  Group,
  Menu,
  Paper,
  RingProgress,
  Select,
  SimpleGrid,
  Skeleton,
  Stack,
  Text,
  ThemeIcon,
} from "@mantine/core";
import {
  AlertTriangle,
  ArrowRight,
  CalendarClock,
  CalendarDays,
  Eye,
  Inbox,
  MoreHorizontal,
  Package,
  Ruler,
  Train,
  TrainFront,
  Weight,
} from "lucide-react";
import type { ColumnDef } from "@edr/ui-common";
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";

import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import FleetToolbar from "@/components/fleet/FleetToolbar";
import { useFleetViewMode } from "@/components/fleet/useFleetViewMode";
import {
  BookingPipeline,
  HeroChip,
  totalBookingCount,
  WindowStatusPill,
} from "@/components/trainScheduling/batchVisuals";
import { RouteCorridor } from "@/components/trainScheduling/scheduleVisuals";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import { FREIGHT_BRAND, FREIGHT_BRAND_DARK } from "@/theme/freight-brand";
import { useQuery } from "@tanstack/react-query";
import { api } from "@/services/api";
import type { BatchBoardSchedule } from "@/types/trainScheduling";

const fmtTons = (n: number) =>
  `${n.toLocaleString(undefined, { maximumFractionDigits: 1 })} t`;

const fmtMeters = (n: number) =>
  `${n.toLocaleString(undefined, { maximumFractionDigits: 1 })} m`;

const fmtScheduleDate = (iso: string | null) =>
  iso
    ? new Intl.DateTimeFormat("en-GB", {
        weekday: "short",
        day: "2-digit",
        month: "short",
        hour: "2-digit",
        minute: "2-digit",
        hour12: false,
        timeZone: "Africa/Addis_Ababa",
      }).format(new Date(iso)) + " EAT"
    : "No date";

const splitDate = (iso: string | null) => {
  if (!iso) return { day: "—", time: "" };
  const date = new Date(iso);
  if (Number.isNaN(date.getTime())) return { day: "—", time: "" };
  return {
    day: new Intl.DateTimeFormat("en-GB", {
      day: "2-digit",
      month: "short",
      year: "numeric",
      timeZone: "Africa/Addis_Ababa",
    }).format(date),
    time:
      new Intl.DateTimeFormat("en-GB", {
        hour: "2-digit",
        minute: "2-digit",
        hour12: false,
        timeZone: "Africa/Addis_Ababa",
      }).format(date) + " EAT",
  };
};

/** Capacity ring color: gold normally, red once over capacity. */
function ringColor(pct: number) {
  if (pct >= 100) return "#fa5252";
  return "#F2A516";
}

/** Capacity ring that keeps the explicit allocated/max numbers underneath. */
function CapacityRing({
  pct,
  label,
  current,
  max,
}: {
  pct: number;
  label: string;
  current: string;
  max: string;
}) {
  const clamped = Math.min(100, Math.max(0, pct));
  const color = ringColor(pct);
  return (
    <Stack gap={4} align="center" style={{ flex: 1 }}>
      <RingProgress
        size={104}
        thickness={9}
        roundCaps
        sections={[{ value: clamped, color }]}
        rootColor="var(--mantine-color-gray-1)"
        label={
          <Stack gap={0} align="center">
            <Text ta="center" size="lg" fw={800} lh={1} style={{ color }}>
              {Math.round(pct)}%
            </Text>
            <Text ta="center" size="9px" c="dimmed" fw={600}>
              {label}
            </Text>
          </Stack>
        }
      />
      <Stack gap={0} align="center">
        <Text size="xs" fw={700} c="dark.4">
          {current}
        </Text>
        <Text size="xs" c="dimmed">
          of {max}
        </Text>
      </Stack>
    </Stack>
  );
}

/** Small percent chip used in the table's capacity column. */
function CapacityChip({
  icon: Icon,
  pct,
  text,
}: {
  icon: typeof Weight;
  pct: number | null;
  text: string;
}) {
  const over = pct != null && pct >= 100;
  return (
    <Group
      gap={4}
      wrap="nowrap"
      style={{
        padding: "2px 8px",
        borderRadius: 8,
        background: over ? "var(--mantine-color-red-0)" : "var(--mantine-color-gray-1)",
        border: `1px solid ${over ? "var(--mantine-color-red-2)" : "var(--mantine-color-gray-2)"}`,
      }}
    >
      <Icon size={12} color={over ? "var(--mantine-color-red-6)" : "var(--mantine-color-gray-6)"} />
      <Text size="xs" fw={700} c={over ? "red.7" : "gray.7"} lh={1.2}>
        {pct != null ? `${Math.round(pct)}%` : "—"}
      </Text>
      <Text size="10px" c="dimmed" lh={1.2}>
        {text}
      </Text>
    </Group>
  );
}

function weightPctOf(s: BatchBoardSchedule) {
  return s.capacity.maxWeightTons && s.capacity.maxWeightTons > 0
    ? (s.capacity.usedWeightTons / s.capacity.maxWeightTons) * 100
    : null;
}
function lengthPctOf(s: BatchBoardSchedule) {
  return s.capacity.maxLengthMeters && s.capacity.maxLengthMeters > 0
    ? (s.capacity.allocatedLengthMeters / s.capacity.maxLengthMeters) * 100
    : null;
}

function ScheduleCard({ schedule }: { schedule: BatchBoardSchedule }) {
  const navigate = useNavigate();
  const { capacity, counts, locomotive } = schedule;

  const lengthPct = lengthPctOf(schedule);
  const weightPct = weightPctOf(schedule);

  const totalBookings = totalBookingCount(counts);

  return (
    <Paper
      className="bb-card"
      radius="lg"
      withBorder
      style={{
        borderColor: "var(--mantine-color-gray-2)",
        background: "white",
        overflow: "hidden",
        cursor: "pointer",
        display: "flex",
        flexDirection: "column",
      }}
      onClick={() =>
        navigate(`/dashboard/operations/batch-board/${schedule.scheduleId}`)
      }
    >
      <Stack gap="md" p="lg" style={{ flex: 1 }}>
        {/* header */}
        <Group justify="space-between" align="flex-start" wrap="nowrap">
          <Group gap="sm" wrap="nowrap" style={{ minWidth: 0 }}>
            <ThemeIcon size={44} radius="md" variant="light" color="#F2A516">
              <Train size={22} />
            </ThemeIcon>
            <Box style={{ minWidth: 0 }}>
              <Text fw={800} size="md" truncate style={{ letterSpacing: 0.2 }}>
                {schedule.trainNumber ?? schedule.routeName ?? "Schedule"}
              </Text>
              <Text
                size="10px"
                fw={700}
                tt="uppercase"
                c="dimmed"
                style={{ letterSpacing: 0.8 }}
              >
                Freight schedule · {schedule.status}
              </Text>
            </Box>
          </Group>
          <WindowStatusPill status={schedule.bookingWindowStatus} />
        </Group>

        <RouteCorridor
          origin={schedule.origin}
          destination={schedule.destination}
          variant="compact"
        />

        <Group gap={6} wrap="wrap">
          <HeroChip icon={<CalendarDays size={12} />}>
            {fmtScheduleDate(schedule.scheduleDate)}
          </HeroChip>
          {locomotive ? (
            <HeroChip icon={<TrainFront size={12} />}>
              {locomotive.code} · {fmtTons(locomotive.maxPullWeightTons)}
            </HeroChip>
          ) : null}
        </Group>

        {!locomotive ? (
          <Alert
            color="red"
            radius="md"
            icon={<AlertTriangle size={15} />}
            py={6}
            styles={{ message: { fontSize: 12 } }}
          >
            No locomotive assigned — wagon allocation cannot run.
          </Alert>
        ) : null}

        {/* capacity: weight + length rings + wagons (numbers preserved) */}
        <Box
          py="sm"
          px="xs"
          style={{
            borderRadius: 14,
            background: "var(--mantine-color-gray-0)",
            border: "1px solid var(--mantine-color-gray-1)",
          }}
        >
          <Group justify="space-around" align="center" wrap="nowrap" gap="xs">
            {weightPct != null ? (
              <CapacityRing
                pct={weightPct}
                label="WEIGHT"
                current={fmtTons(capacity.usedWeightTons)}
                max={fmtTons(capacity.maxWeightTons ?? 0)}
              />
            ) : null}

            <Stack gap={0} align="center" style={{ flex: 1 }}>
              <ThemeIcon size={34} radius="md" variant="light" color="gray">
                <Package size={17} />
              </ThemeIcon>
              <Text fw={800} size="26px" c="dark.5" lh={1.1} mt={6}>
                {capacity.allocatedWagons}
              </Text>
              <Text size="9px" fw={700} c="gray.6" tt="uppercase" style={{ letterSpacing: 0.5 }}>
                Wagons
              </Text>
              <Text size="xs" c="dimmed">
                allocated
              </Text>
            </Stack>

            {lengthPct != null ? (
              <CapacityRing
                pct={lengthPct}
                label="LENGTH"
                current={fmtMeters(capacity.allocatedLengthMeters)}
                max={fmtMeters(capacity.maxLengthMeters ?? 0)}
              />
            ) : null}
          </Group>
        </Box>

        {/* booking pipeline */}
        <Box>
          <Group justify="space-between" mb={6}>
            <Group gap={5} wrap="nowrap">
              <Package size={13} color="var(--mantine-color-gray-6)" />
              <Text size="xs" fw={700} c="gray.7" tt="uppercase" style={{ letterSpacing: 0.4 }}>
                Booking pipeline
              </Text>
            </Group>
            <Text size="xs" fw={700} c="dark.4">
              {totalBookings} booking{totalBookings === 1 ? "" : "s"}
            </Text>
          </Group>
          <BookingPipeline counts={counts} />
        </Box>
      </Stack>

      {/* CTA */}
      <Box px="lg" pb="lg">
        <Button
          fullWidth
          radius="md"
          variant="gradient"
          gradient={{ from: FREIGHT_BRAND, to: FREIGHT_BRAND_DARK, deg: 135 }}
          rightSection={<ArrowRight size={16} className="bb-arrow" />}
          onClick={(e) => {
            e.stopPropagation();
            navigate(`/dashboard/operations/batch-board/${schedule.scheduleId}`);
          }}
        >
          View batch windows
        </Button>
      </Box>
    </Paper>
  );
}

function CardSkeleton() {
  return (
    <Paper radius="lg" withBorder style={{ overflow: "hidden" }}>
      <Stack gap="md" p="lg">
        <Group justify="space-between">
          <Group gap="sm">
            <Skeleton height={44} width={44} radius="md" />
            <Skeleton height={32} width={120} />
          </Group>
          <Skeleton height={22} width={90} radius="xl" />
        </Group>
        <Skeleton height={120} radius="md" />
        <Skeleton height={10} radius="xl" />
        <Skeleton height={36} radius="md" />
      </Stack>
    </Paper>
  );
}

export default function BatchBoardPage() {
  const navigate = useNavigate();
  const { data, isLoading, isError, isFetching, refetch } = useQuery(
    api.trainScheduling.batchBoard.queryOptions({ refetchInterval: 30_000 }),
  );
  const { viewMode, setViewMode } = useFleetViewMode("batch-board");
  const { pagination, setPagination } = usePagination({ pageSize: 10 });
  const [search, setSearch] = useState("");
  const [windowFilter, setWindowFilter] = useState("ALL");

  const schedules = data ?? [];

  const summary = useMemo(() => {
    const openWindows = schedules.filter((s) => s.bookingWindowStatus === "OPEN").length;
    const totalBookings = schedules.reduce((sum, s) => sum + totalBookingCount(s.counts), 0);
    const totalWagons = schedules.reduce((sum, s) => sum + s.capacity.allocatedWagons, 0);
    return { openWindows, totalBookings, totalWagons };
  }, [schedules]);

  const filtered = useMemo(() => {
    const query = search.trim().toLowerCase();
    return schedules.filter((s) => {
      if (windowFilter !== "ALL" && s.bookingWindowStatus !== windowFilter) return false;
      if (!query) return true;
      const haystack = [
        s.trainNumber,
        s.routeName,
        s.origin,
        s.destination,
        s.locomotive?.code,
        s.status,
        s.bookingWindowStatus,
      ]
        .filter(Boolean)
        .join(" ")
        .toLowerCase();
      return haystack.includes(query);
    });
  }, [schedules, search, windowFilter]);

  const pageCount = Math.max(1, Math.ceil(filtered.length / pagination.pageSize));
  const paged = useMemo(() => {
    const start = pagination.pageIndex * pagination.pageSize;
    return filtered.slice(start, start + pagination.pageSize);
  }, [filtered, pagination]);

  const columns = useMemo((): ColumnDef<BatchBoardSchedule>[] => {
    const headerClassName = ruleEngineTable.headerCell;
    const cellClassName = ruleEngineTable.bodyCell;
    return [
      {
        id: "train",
        header: "Train / Route",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => (
          <Group gap="sm" wrap="nowrap">
            <ThemeIcon size={34} radius="md" variant="light" color="#F2A516">
              <Train size={17} />
            </ThemeIcon>
            <Stack gap={2} style={{ minWidth: 0 }}>
              <Text size="sm" fw={700} lh={1.2} truncate>
                {row.original.trainNumber ?? row.original.routeName ?? "Schedule"}
              </Text>
              <Box maw={220}>
                <RouteCorridor
                  origin={row.original.origin}
                  destination={row.original.destination}
                  variant="compact"
                />
              </Box>
            </Stack>
          </Group>
        ),
      },
      {
        id: "date",
        header: "Departure",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => {
          const { day, time } = splitDate(row.original.scheduleDate);
          return (
            <Group gap="sm" wrap="nowrap">
              <Box
                style={{
                  display: "flex",
                  alignItems: "center",
                  justifyContent: "center",
                  width: 34,
                  height: 34,
                  borderRadius: 9,
                  background: "var(--mantine-color-orange-0)",
                  color: "#B26C09",
                  flexShrink: 0,
                }}
              >
                <CalendarClock size={16} />
              </Box>
              <Stack gap={0}>
                <Text size="sm" fw={600} lh={1.2}>
                  {day}
                </Text>
                <Text size="xs" c="dimmed" lh={1.2}>
                  {time || "—"}
                </Text>
              </Stack>
            </Group>
          );
        },
      },
      {
        id: "window",
        header: "Window",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => <WindowStatusPill status={row.original.bookingWindowStatus} />,
      },
      {
        id: "loco",
        header: "Locomotive",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) =>
          row.original.locomotive ? (
            <Group gap={6} wrap="nowrap">
              <TrainFront size={14} color="var(--mantine-color-gray-5)" />
              <Stack gap={0}>
                <Text size="sm" fw={600} lh={1.2}>
                  {row.original.locomotive.code}
                </Text>
                <Text size="10px" c="dimmed" lh={1.2}>
                  {fmtTons(row.original.locomotive.maxPullWeightTons)} pull
                </Text>
              </Stack>
            </Group>
          ) : (
            <Text size="xs" c="red.6" fw={600}>
              No loco
            </Text>
          ),
      },
      {
        id: "capacity",
        header: "Capacity",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => (
          <Group gap={6} wrap="nowrap">
            <CapacityChip icon={Weight} pct={weightPctOf(row.original)} text="wt" />
            <CapacityChip icon={Ruler} pct={lengthPctOf(row.original)} text="len" />
            <Group
              gap={4}
              wrap="nowrap"
              style={{
                padding: "2px 8px",
                borderRadius: 8,
                background: "var(--mantine-color-edr-green-0)",
                border: "1px solid var(--mantine-color-edr-green-1)",
              }}
            >
              <Package size={12} color="var(--mantine-color-edr-green-7)" />
              <Text size="xs" fw={700} c="edr-green.8" lh={1.2}>
                {row.original.capacity.allocatedWagons}
              </Text>
              <Text size="10px" c="dimmed" lh={1.2}>
                wgn
              </Text>
            </Group>
          </Group>
        ),
      },
      {
        id: "bookings",
        header: "Bookings",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => {
          const total = totalBookingCount(row.original.counts);
          return (
            <Stack gap={4} style={{ minWidth: 130 }}>
              <Text size="sm" fw={700} c="dark.4" lh={1.2}>
                {total} booking{total === 1 ? "" : "s"}
              </Text>
              <BookingPipeline counts={row.original.counts} size={10} />
            </Stack>
          );
        },
      },
      {
        id: "actions",
        header: "",
        meta: { headerClassName, cellClassName: `${cellClassName} whitespace-nowrap` },
        cell: ({ row }) => (
          <Group justify="flex-end" wrap="nowrap" onClick={(e) => e.stopPropagation()}>
            <Menu position="bottom-end" withinPortal shadow="md" width={180}>
              <Menu.Target>
                <ActionIcon variant="subtle" color="gray" aria-label="Row actions">
                  <MoreHorizontal size={16} />
                </ActionIcon>
              </Menu.Target>
              <Menu.Dropdown>
                <Menu.Item
                  leftSection={<Eye size={15} />}
                  onClick={() =>
                    navigate(`/dashboard/operations/batch-board/${row.original.scheduleId}`)
                  }
                >
                  View windows
                </Menu.Item>
              </Menu.Dropdown>
            </Menu>
          </Group>
        ),
      },
    ];
  }, [navigate]);

  const tableStatus = isLoading ? "loading" : isError ? "error" : "success";

  return (
    <PageContainer>
      <PageHeader
        title="Batch Board"
        subtitle="Active schedules and their booking windows."
        action={
          <Button variant="default" loading={isFetching} onClick={() => void refetch()}>
            Refresh
          </Button>
        }
      />

      <KpiStrip
        loading={isLoading}
        items={[
          {
            label: "Active schedules",
            value: schedules.length,
            hint: "on the board right now",
            icon: Train,
          },
          {
            label: "Open windows",
            value: summary.openWindows,
            hint: "accepting bookings",
            icon: CalendarDays,
          },
          {
            label: "Bookings in play",
            value: summary.totalBookings,
            hint: `${summary.totalWagons} wagons allocated`,
            icon: Package,
          },
        ]}
      />

      <Card p={0}>
        <Stack gap={0}>
          <Box px="md" pt="md" pb="sm" w="100%">
            <FleetToolbar
              search={search}
              onSearchChange={setSearch}
              searchPlaceholder="Search schedules…"
              viewMode={viewMode}
              onViewModeChange={setViewMode}
              filters={
                <Select
                  size="sm"
                  radius="lg"
                  value={windowFilter}
                  onChange={(v) => v && setWindowFilter(v)}
                  data={[
                    { value: "ALL", label: "All windows" },
                    { value: "OPEN", label: "Open" },
                    { value: "FULL", label: "Full" },
                    { value: "CLOSED", label: "Closed" },
                  ]}
                  w={150}
                  styles={{ input: { borderColor: "var(--mantine-color-gray-3)" } }}
                />
              }
            />
          </Box>

          {viewMode === "table" ? (
            <DataTable
              columns={columns}
              data={paged}
              status={tableStatus}
              onRowClick={(schedule) =>
                navigate(`/dashboard/operations/batch-board/${schedule.scheduleId}`)
              }
              error={
                isError
                  ? {
                      message: "Failed to load the batch board.",
                      onRetry: () => void refetch(),
                    }
                  : undefined
              }
              emptyMessage="No active schedules"
              pagination={{
                pageIndex: pagination.pageIndex,
                pageSize: pagination.pageSize,
                pageCount,
                totalCount: filtered.length,
              }}
              tableOptions={{
                manualPagination: true,
                pageCount,
                state: { pagination },
                onPaginationChange: setPagination,
              }}
              containerClassName="border-0 shadow-none bg-transparent"
              footer={({ table, pagination: footerPagination }) => (
                <DataTableFooter
                  table={table}
                  pagination={footerPagination}
                  options={{ labels: { items: "schedules" } }}
                />
              )}
            />
          ) : isLoading ? (
            <SimpleGrid cols={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing="lg" p="md">
              <CardSkeleton />
              <CardSkeleton />
              <CardSkeleton />
            </SimpleGrid>
          ) : filtered.length === 0 ? (
            <Paper radius="lg" p={48} m="md" bg="gray.0">
              <Stack align="center" gap="sm">
                <Box
                  style={{
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    width: 64,
                    height: 64,
                    borderRadius: 20,
                    background: "white",
                    border: "1px solid var(--mantine-color-gray-2)",
                  }}
                >
                  <Inbox size={28} color="var(--mantine-color-gray-5)" />
                </Box>
                <Text fw={700} c="gray.7">
                  No active schedules
                </Text>
                <Text size="sm" c="dimmed" ta="center" maw={380}>
                  Schedules with an open booking window appear here. Create or activate a
                  schedule to get started.
                </Text>
              </Stack>
            </Paper>
          ) : (
            <SimpleGrid cols={{ base: 1, md: 2, lg: 3, xl: 4 }} spacing="lg" p="md">
              {filtered.map((s) => (
                <ScheduleCard key={s.scheduleId} schedule={s} />
              ))}
            </SimpleGrid>
          )}
        </Stack>
      </Card>
    </PageContainer>
  );
}
