import { useMemo, useState } from "react";
import {
  Alert,
  Badge,
  Button,
  Card,
  Center,
  Group,
  Loader,
  SimpleGrid,
  Table,
  Tabs,
  Text,
  Tooltip,
} from "@mantine/core";
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
import { AlertTriangle, PackageCheck, PackageOpen, TrainFront, Warehouse } from "lucide-react";

import { PageContainer, PageHeader } from "@/components/page";
import ListControls from "@/components/common/ListControls";
// Generic list footer — already shared by the fleet and train-scheduling lists
// despite the ruleEngine path.
import RuleEngineListFooter from "@/components/ruleEngine/RuleEngineListFooter";
import { useListControls } from "@/hooks/useListControls";
import { useToast } from "@/hooks/use-toast";
import { api } from "@/services/api";
import type { IntercityRideAlongRow } from "@/types/trainScheduling";

/**
 * Intercity cargo across every train.
 *
 * Intercity bookings never get their own train — they ride whichever
 * import/export train passes through their corridor — so the work is spread over
 * other people's schedules. This is the one place it's all visible.
 */

const fmtTons = (t: number | null) => (t == null ? "—" : `${t} t`);

/** A booking can only be worked where the train actually is. */
const atOrigin = (r: IntercityRideAlongRow) =>
  Boolean(r.trainAtYardId) && r.trainAtYardId === r.originYardId;
const atDestination = (r: IntercityRideAlongRow) =>
  Boolean(r.trainAtYardId) && r.trainAtYardId === r.destinationYardId;

const isWaiting = (r: IntercityRideAlongRow) =>
  !r.loadedAt && r.status !== "IN_TRANSIT" && r.status !== "COMPLETED";
const isRiding = (r: IntercityRideAlongRow) => r.status === "IN_TRANSIT";
const isDone = (r: IntercityRideAlongRow) => r.status === "COMPLETED";

/**
 * A yard that can't handle THIS booking's cargo can never work it — surface that
 * while the train is still coming, not when the load is refused. Containers need
 * a facility with a stacker (Indode, Modjo, Dire Dawa); bulk is handled at all of
 * them.
 */
function FacilityCell({
  yard,
  has,
  freightType,
}: {
  yard: string | null;
  has: boolean | null;
  freightType: string | null;
}) {
  if (!yard) return <Text size="sm">—</Text>;
  if (has) return <Text size="sm">{yard}</Text>;
  return (
    <Tooltip
      label={`${yard} cannot handle ${(freightType ?? "this").toLowerCase()} cargo — no facility here, or no equipment for it`}
      withArrow
      multiline
      w={260}
    >
      <Group gap={4} wrap="nowrap">
        <AlertTriangle size={13} color="var(--mantine-color-red-6)" />
        <Text size="sm" c="red">
          {yard}
        </Text>
      </Group>
    </Tooltip>
  );
}

const apiErrorMessage = (error: unknown) => {
  if (error && typeof error === "object" && "response" in error) {
    const message = (error as { response?: { data?: { message?: unknown } } }).response?.data
      ?.message;
    if (Array.isArray(message)) return message.join("; ");
    if (typeof message === "string") return message;
  }
  return error instanceof Error ? error.message : undefined;
};

function Rows({ rows }: { rows: IntercityRideAlongRow[] }) {
  const { toast } = useToast();
  const queryClient = useQueryClient();
  const refresh = () =>
    queryClient.invalidateQueries({
      queryKey: api.trainScheduling.intercityBookings.queryKey(undefined),
    });
  // Same endpoints as the schedule page's ride-along panel — the server still
  // validates the train's recorded checkpoint, payment and yard equipment.
  const load = useMutation(
    api.trainScheduling.loadIntercityBooking.mutationOptions({
      onSuccess: () => {
        toast({ title: "Cargo loaded onto the train" });
        void refresh();
      },
      onError: (error) =>
        toast({ variant: "destructive", title: "Load failed", description: apiErrorMessage(error) }),
    }),
  );
  const unload = useMutation(
    api.trainScheduling.unloadIntercityBooking.mutationOptions({
      onSuccess: () => {
        toast({ title: "Cargo unloaded — booking completed" });
        void refresh();
      },
      onError: (error) =>
        toast({ variant: "destructive", title: "Unload failed", description: apiErrorMessage(error) }),
    }),
  );
  if (rows.length === 0) {
    return (
      <Alert variant="light" color="gray">
        Nothing here.
      </Alert>
    );
  }
  return (
    <Table.ScrollContainer minWidth={900}>
      <Table striped highlightOnHover verticalSpacing="xs">
        <Table.Thead>
          <Table.Tr>
            <Table.Th>Booking</Table.Th>
            <Table.Th>Customer</Table.Th>
            <Table.Th>Load at</Table.Th>
            <Table.Th>Unload at</Table.Th>
            <Table.Th>Train</Table.Th>
            <Table.Th ta="right">Weight</Table.Th>
            <Table.Th>GRN</Table.Th>
            <Table.Th>Status</Table.Th>
            <Table.Th />
          </Table.Tr>
        </Table.Thead>
        <Table.Tbody>
          {rows.map((r) => (
            <Table.Tr key={r.bookingId}>
              <Table.Td>
                <Text fw={600} size="sm">
                  {r.reference ?? r.bookingId.slice(0, 8)}
                </Text>
              </Table.Td>
              <Table.Td>{r.customer ?? "—"}</Table.Td>
              <Table.Td>
                <Group gap={6} wrap="nowrap">
                  <FacilityCell yard={r.origin} has={r.originHasFacility} freightType={r.freightType} />
                  {atOrigin(r) && isWaiting(r) && (
                    <Badge size="xs" color="edr-green" variant="light">
                      train here
                    </Badge>
                  )}
                </Group>
              </Table.Td>
              <Table.Td>
                <Group gap={6} wrap="nowrap">
                  <FacilityCell yard={r.destination} has={r.destinationHasFacility} freightType={r.freightType} />
                  {atDestination(r) && isRiding(r) && (
                    <Badge size="xs" color="edr-green" variant="light">
                      train here
                    </Badge>
                  )}
                </Group>
              </Table.Td>
              <Table.Td>
                {r.trainNumber ? (
                  <Group gap={4} wrap="nowrap">
                    <TrainFront size={13} />
                    <Text size="sm">{r.trainNumber}</Text>
                  </Group>
                ) : (
                  <Text size="sm" c="dimmed">
                    not on a train
                  </Text>
                )}
              </Table.Td>
              <Table.Td ta="right">
                <Text size="sm">{fmtTons(r.weightTons)}</Text>
              </Table.Td>
              <Table.Td>
                <Text size="sm" c={r.grnNumber ? undefined : "dimmed"}>
                  {r.grnNumber ?? "—"}
                </Text>
              </Table.Td>
              <Table.Td>
                <Badge size="sm" variant="light" color="gray">
                  {r.status}
                </Badge>
              </Table.Td>
              <Table.Td>
                <Group gap="xs" justify="flex-end" wrap="nowrap">
                  {/* Work the cargo right here while the train is at the yard. */}
                  {r.trainScheduleId && atOrigin(r) && isWaiting(r) && r.status === "PAID" && (
                    <Button
                      size="compact-xs"
                      variant="light"
                      leftSection={<PackageCheck size={13} />}
                      loading={load.isPending}
                      onClick={() =>
                        load.mutate({ scheduleId: r.trainScheduleId as string, bookingId: r.bookingId })
                      }
                    >
                      Load
                    </Button>
                  )}
                  {r.trainScheduleId && atDestination(r) && isRiding(r) && (
                    <Button
                      size="compact-xs"
                      variant="light"
                      color="orange"
                      leftSection={<PackageOpen size={13} />}
                      loading={unload.isPending}
                      onClick={() =>
                        unload.mutate({ scheduleId: r.trainScheduleId as string, bookingId: r.bookingId })
                      }
                    >
                      Unload
                    </Button>
                  )}
                </Group>
              </Table.Td>
            </Table.Tr>
          ))}
        </Table.Tbody>
      </Table>
    </Table.ScrollContainer>
  );
}

function Stat({
  icon,
  label,
  value,
  color,
}: {
  icon: React.ReactNode;
  label: string;
  value: React.ReactNode;
  color?: string;
}) {
  return (
    <Card withBorder radius="md" padding="md">
      <Group gap="sm" wrap="nowrap">
        {icon}
        <div>
          <Text size="xs" c="dimmed" tt="uppercase" fw={700}>
            {label}
          </Text>
          <Text fw={800} fz={22} lh={1.1} c={color}>
            {value}
          </Text>
        </div>
      </Group>
    </Card>
  );
}

export default function IntercityPage() {
  const [tab, setTab] = useState("waiting");
  const { data: rows = [], isLoading } = useQuery(
    api.trainScheduling.intercityBookings.queryOptions({ input: undefined }),
  );

  const waiting = useMemo(() => rows.filter(isWaiting), [rows]);
  const riding = useMemo(() => rows.filter(isRiding), [rows]);
  const done = useMemo(() => rows.filter(isDone), [rows]);
  // A booking whose end has no equipment is stuck until someone flags the yard.
  const blocked = useMemo(
    () =>
      rows.filter(
        (r) => !isDone(r) && (!r.originHasFacility || !r.destinationHasFacility),
      ),
    [rows],
  );

  // Controls follow the active tab, so search/date/paging always describe what
  // is on screen. Panels unmount when hidden (keepMounted={false}) so a hidden
  // tab can never render another tab's paged slice.
  const active = tab === "riding" ? riding : tab === "done" ? done : waiting;
  const controls = useListControls(active, {
    searchKeys: ["reference", "grnNumber", "customer", "origin", "destination", "trainNumber"],
    dateKey: "loadedAt",
  });

  return (
    <PageContainer>
      <PageHeader
        title="Intercity"
        subtitle="Domestic cargo riding passing trains — loaded at its origin facility, unloaded at its destination."
      />

      {isLoading ? (
        <Center py="xl">
          <Loader />
        </Center>
      ) : (
        <>
          <SimpleGrid cols={{ base: 1, xs: 2, md: 4 }} spacing="sm" mb="md">
            <Stat
              icon={<PackageCheck size={18} />}
              label="Waiting to load"
              value={waiting.length}
            />
            <Stat icon={<TrainFront size={18} />} label="On a train" value={riding.length} />
            <Stat icon={<Warehouse size={18} />} label="Completed" value={done.length} />
            <Stat
              icon={<AlertTriangle size={18} />}
              label="Cannot handle"
              value={blocked.length}
              color={blocked.length > 0 ? "red" : undefined}
            />
          </SimpleGrid>

          {blocked.length > 0 && (
            <Alert
              variant="light"
              color="red"
              icon={<AlertTriangle size={16} />}
              title={`${blocked.length} booking${blocked.length === 1 ? "" : "s"} cannot be handled`}
              mb="md"
            >
              Their origin or destination yard cannot handle that cargo — no facility, or no
              equipment for it. Containers need Indode, Modjo or Dire Dawa; bulk is handled at
              any facility. Adjust the yard in Configuration → Yards.
            </Alert>
          )}

          <Card withBorder radius="md" padding="md">
            <Tabs value={tab} onChange={(v) => setTab(v ?? "waiting")}>
              <Tabs.List mb="md">
                <Tabs.Tab
                  value="waiting"
                  rightSection={
                    <Badge size="xs" variant="light">
                      {waiting.length}
                    </Badge>
                  }
                >
                  Waiting to load
                </Tabs.Tab>
                <Tabs.Tab
                  value="riding"
                  rightSection={
                    <Badge size="xs" variant="light">
                      {riding.length}
                    </Badge>
                  }
                >
                  On a train
                </Tabs.Tab>
                <Tabs.Tab
                  value="done"
                  rightSection={
                    <Badge size="xs" variant="light">
                      {done.length}
                    </Badge>
                  }
                >
                  Completed
                </Tabs.Tab>
              </Tabs.List>

              <ListControls
                search={controls.search}
                onSearchChange={controls.setSearch}
                searchPlaceholder="Reference, GRN, customer, train…"
                dateFrom={controls.dateFrom}
                onDateFromChange={controls.setDateFrom}
                dateTo={controls.dateTo}
                onDateToChange={controls.setDateTo}
                dateLabel="Loaded"
                hasFilters={controls.hasFilters}
                onReset={controls.reset}
              />

              <Tabs.Panel value="waiting" keepMounted={false}>
                <Rows rows={controls.pagedRows} />
              </Tabs.Panel>
              <Tabs.Panel value="riding" keepMounted={false}>
                <Rows rows={controls.pagedRows} />
              </Tabs.Panel>
              <Tabs.Panel value="done" keepMounted={false}>
                <Rows rows={controls.pagedRows} />
              </Tabs.Panel>
            </Tabs>

            <RuleEngineListFooter
              pagination={controls.pagination}
              pageCount={controls.pageCount}
              totalCount={controls.totalCount}
              itemLabel="bookings"
              onPaginationChange={controls.setPagination}
            />
            <Text size="xs" c="dimmed" mt="sm">
              Load and Unload appear on a row while its train is recorded at that yard ("train
              here"); the same actions also live on the train's schedule page.
            </Text>
          </Card>
        </>
      )}
    </PageContainer>
  );
}
