import { FormEvent, useMemo, useState } from "react";
import { Ban, CircleCheck, Edit, Eye, Plus, Route as RouteIcon, Trash2 } from "lucide-react";
import type { ColumnDef } from "@edr/ui-common";
import {
  ActionIcon,
  Badge,
  Box,
  Button,
  Card,
  Group,
  Modal,
  Select,
  SimpleGrid,
  Stack,
  Text,
  TextInput,
  Tooltip,
} from "@mantine/core";

import { useMutation, useQuery } from "@tanstack/react-query";

import { KpiStrip, PageContainer, PageHeader } from "@/components/page";
import FleetToolbar from "@/components/fleet/FleetToolbar";
import { useFleetViewMode } from "@/components/fleet/useFleetViewMode";
import RuleEngineListFooter from "@/components/ruleEngine/RuleEngineListFooter";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import { api } from "@/services/api";
import { useToast } from "@/hooks/use-toast";
import type { RouteRecord, YardRef } from "@/services/routes.service";
import { DataTable, DataTableFooter, usePagination } from "@edr/ui-common";

type RouteFormState = {
  name: string;
  milestones: string[];
};

const emptyForm = (): RouteFormState => ({ name: "", milestones: ["", ""] });

const yardLabel = (yard?: YardRef | null) => (yard ? `${yard.label} (${yard.code})` : "—");

const routeStops = (route: RouteRecord) =>
  (route.milestones ?? [])
    .sort((left, right) => left.sequenceNo - right.sequenceNo)
    .map((milestone) => milestone.yard?.label ?? milestone.yard?.code ?? milestone.yardId);

const normalizeRouteError = (error: unknown) => {
  const responseData = (error as { response?: { data?: unknown } })?.response?.data;
  const data =
    responseData && typeof responseData === "object"
      ? (responseData as Record<string, unknown>)
      : undefined;
  const rawMessage = data?.message ?? data?.error ?? (error as Error)?.message;
  return Array.isArray(rawMessage)
    ? rawMessage.join(", ")
    : rawMessage
      ? String(rawMessage)
      : "Save failed";
};

export default function RoutesPage() {
  const [search, setSearch] = useState("");
  const [formOpen, setFormOpen] = useState(false);
  const [viewing, setViewing] = useState<RouteRecord | null>(null);
  const [editing, setEditing] = useState<RouteRecord | null>(null);
  const [form, setForm] = useState<RouteFormState>(emptyForm());
  const { viewMode, setViewMode } = useFleetViewMode("routes");
  const { pagination, setPagination } = usePagination({ pageSize: 10 });
  const { toast } = useToast();

  const routesQuery = useQuery(api.routes.list.queryOptions());
  const yardsQuery = useQuery(api.routes.yards.queryOptions());
  const createMutation = useMutation(api.routes.create.mutationOptions());
  const updateMutation = useMutation(api.routes.update.mutationOptions());
  const deactivateMutation = useMutation(api.routes.deactivate.mutationOptions());

  const filteredRoutes = useMemo(() => {
    const query = search.trim().toLowerCase();
    if (!query) return routesQuery.data ?? [];
    return (routesQuery.data ?? []).filter((route) => {
      const searchable = [
        route.name,
        route.originYard?.label,
        route.originYard?.code,
        route.destinationYard?.label,
        route.destinationYard?.code,
        ...routeStops(route),
      ]
        .filter(Boolean)
        .join(" ")
        .toLowerCase();
      return searchable.includes(query);
    });
  }, [routesQuery.data, search]);

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

  const allRoutes = routesQuery.data ?? [];
  const activeCount = allRoutes.filter((route) => route.isActive).length;

  const yardOptions = useMemo(
    () =>
      (yardsQuery.data ?? []).map((yard) => ({
        value: yard.id,
        label: `${yard.label} (${yard.code})`,
      })),
    [yardsQuery.data],
  );

  const resetForm = () => {
    setFormOpen(false);
    setEditing(null);
    setForm(emptyForm());
  };

  const openCreate = () => {
    setEditing(null);
    setForm(emptyForm());
    setFormOpen(true);
  };

  const openEdit = (route: RouteRecord) => {
    setEditing(route);
    setForm({
      name: route.name,
      milestones: (route.milestones ?? [])
        .sort((left, right) => left.sequenceNo - right.sequenceNo)
        .map((milestone) => milestone.yardId),
    });
    setFormOpen(true);
  };

  const setMilestone = (index: number, yardId: string) => {
    setForm((current) => ({
      ...current,
      milestones: current.milestones.map((value, currentIndex) =>
        currentIndex === index ? yardId : value,
      ),
    }));
  };

  const addMilestone = () => {
    setForm((current) => ({ ...current, milestones: [...current.milestones, ""] }));
  };

  const removeMilestone = (index: number) => {
    setForm((current) => ({
      ...current,
      milestones: current.milestones.filter((_, currentIndex) => currentIndex !== index),
    }));
  };

  const handleSubmit = async (event: FormEvent) => {
    event.preventDefault();
    if (!form.name.trim()) {
      toast({ title: "Save failed", description: "Route name is required", variant: "destructive" });
      return;
    }
    if (form.milestones.length < 2 || form.milestones.some((yardId) => !yardId)) {
      toast({
        title: "Save failed",
        description: "Select at least an origin and destination yard",
        variant: "destructive",
      });
      return;
    }

    try {
      const payload = {
        name: form.name.trim(),
        milestones: form.milestones.map((yardId) => ({ yardId })),
        isActive: editing?.isActive ?? true,
      };
      if (editing) {
        await updateMutation.mutateAsync({ id: editing.id, data: payload });
        toast({ title: "Route updated" });
      } else {
        await createMutation.mutateAsync(payload);
        toast({ title: "Route created" });
      }
      resetForm();
    } catch (error) {
      toast({ title: "Save failed", description: normalizeRouteError(error), variant: "destructive" });
    }
  };

  const handleDeactivate = async (route: RouteRecord) => {
    try {
      await deactivateMutation.mutateAsync(route.id);
      toast({ title: "Route deactivated" });
    } catch {
      toast({ title: "Deactivate failed", description: "Could not deactivate route", variant: "destructive" });
    }
  };

  const isSaving = createMutation.isPending || updateMutation.isPending;

  const availableOptionsForIndex = (index: number) => {
    const selectedByOthers = new Set(
      form.milestones.filter((value, currentIndex) => currentIndex !== index && value),
    );
    return yardOptions.filter(
      (option) => option.value === form.milestones[index] || !selectedByOthers.has(option.value),
    );
  };

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

  const columns = useMemo((): ColumnDef<RouteRecord>[] => {
    const headerClassName = ruleEngineTable.headerCell;
    const cellClassName = ruleEngineTable.bodyCell;
    return [
      { id: "name", header: "Name", meta: { headerClassName, cellClassName }, cell: ({ row }) => row.original.name },
      {
        id: "origin",
        header: "Origin",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => yardLabel(row.original.originYard),
      },
      {
        id: "destination",
        header: "Destination",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => yardLabel(row.original.destinationYard),
      },
      {
        id: "milestones",
        header: "Milestones",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => Math.max((row.original.milestones?.length ?? 0) - 2, 0),
      },
      {
        id: "status",
        header: "Status",
        meta: { headerClassName, cellClassName },
        cell: ({ row }) => (
          <Badge color={row.original.isActive ? "edr-green" : "gray"} variant="light" size="sm">
            {row.original.isActive ? "Active" : "Inactive"}
          </Badge>
        ),
      },
      {
        id: "actions",
        header: "Actions",
        meta: { headerClassName, cellClassName: `${cellClassName} whitespace-nowrap` },
        cell: ({ row }) => (
          <Group gap={4} justify="flex-end" wrap="nowrap">
            <Tooltip label="View">
              <ActionIcon variant="subtle" color="gray" onClick={() => setViewing(row.original)}>
                <Eye size={16} />
              </ActionIcon>
            </Tooltip>
            <Tooltip label="Edit">
              <ActionIcon variant="subtle" color="gray" onClick={() => openEdit(row.original)}>
                <Edit size={16} />
              </ActionIcon>
            </Tooltip>
            <Tooltip label="Deactivate">
              <ActionIcon
                variant="subtle"
                color="red"
                disabled={!row.original.isActive || deactivateMutation.isPending}
                onClick={() => handleDeactivate(row.original)}
              >
                <Trash2 size={16} />
              </ActionIcon>
            </Tooltip>
          </Group>
        ),
      },
    ];
  }, [deactivateMutation.isPending]);

  return (
    <PageContainer>
      <PageHeader
        title="Routes"
        subtitle="Define rail corridors and their ordered yard stops used by train scheduling."
        action={
          <Button leftSection={<Plus size={18} />} onClick={openCreate}>
            Add route
          </Button>
        }
      />

      <KpiStrip
        loading={routesQuery.isLoading}
        items={[
          { label: "Total routes", value: allRoutes.length, icon: RouteIcon },
          { label: "Active", value: activeCount, icon: CircleCheck, color: "edr-green" },
          {
            label: "Inactive",
            value: allRoutes.length - activeCount,
            icon: Ban,
            color: "gray",
          },
        ]}
      />

      <Card radius="lg" padding={0} withBorder>
        <Stack gap={0}>
          <Box px="md" pt="md" pb="sm" w="100%">
            <FleetToolbar
              search={search}
              onSearchChange={setSearch}
              searchPlaceholder="Search routes…"
              viewMode={viewMode}
              onViewModeChange={setViewMode}
            />
          </Box>

          {viewMode === "table" ? (
            <DataTable
              columns={columns}
              data={pagedRoutes}
              status={tableStatus}
              emptyMessage="No routes found"
              pagination={{
                pageIndex: pagination.pageIndex,
                pageSize: pagination.pageSize,
                pageCount,
                totalCount: filteredRoutes.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: "routes" } }}
                />
              )}
            />
          ) : (
            <Stack gap={0}>
              {tableStatus === "loading" ? (
                <Text py="xl" ta="center" c="dimmed" size="sm">
                  Loading…
                </Text>
              ) : !pagedRoutes.length ? (
                <Text py="xl" ta="center" c="dimmed" size="sm">
                  No routes found
                </Text>
              ) : (
                <SimpleGrid cols={{ base: 1, sm: 2, lg: 3 }} spacing="md" p="md">
                  {pagedRoutes.map((route) => (
                    <Card key={route.id} radius="lg" padding="lg" withBorder>
                      <Stack gap="sm">
                        <Group justify="space-between">
                          <Text fw={600}>{route.name}</Text>
                          <Badge color={route.isActive ? "edr-green" : "gray"} variant="light" size="sm">
                            {route.isActive ? "Active" : "Inactive"}
                          </Badge>
                        </Group>
                        <Text size="sm" c="dimmed">
                          {yardLabel(route.originYard)} → {yardLabel(route.destinationYard)}
                        </Text>
                        <Text size="xs" c="dimmed">
                          {Math.max((route.milestones?.length ?? 0) - 2, 0)} intermediate milestones
                        </Text>
                        <Group gap={6} justify="flex-end">
                          <Button variant="light" size="compact-sm" onClick={() => setViewing(route)}>
                            View
                          </Button>
                          <Button variant="light" size="compact-sm" onClick={() => openEdit(route)}>
                            Edit
                          </Button>
                        </Group>
                      </Stack>
                    </Card>
                  ))}
                </SimpleGrid>
              )}
              <RuleEngineListFooter
                pagination={pagination}
                pageCount={pageCount}
                totalCount={filteredRoutes.length}
                itemLabel="routes"
                onPaginationChange={setPagination}
              />
            </Stack>
          )}
        </Stack>
      </Card>

      <Modal
        opened={formOpen}
        onClose={resetForm}
        title={<Text fw={600}>{editing ? "Edit Route" : "Add Route"}</Text>}
        size="lg"
        radius="lg"
        centered
      >
        <form onSubmit={handleSubmit}>
          <Stack gap="md">
            <TextInput
              label="Name"
              value={form.name}
              onChange={(e) => setForm((current) => ({ ...current, name: e.currentTarget.value }))}
            />
            <Group justify="space-between">
              <Text size="sm" fw={500}>
                Stops
              </Text>
              <Button type="button" variant="light" size="compact-sm" onClick={addMilestone}>
                Add milestone
              </Button>
            </Group>
            {form.milestones.map((yardId, index) => {
              const role =
                index === 0
                  ? "Origin"
                  : index === form.milestones.length - 1
                    ? "Destination"
                    : "Milestone";
              return (
                <Group key={`${role}-${index}`} align="flex-end" wrap="nowrap">
                  <Text w={100} size="sm" fw={500}>
                    {role}
                  </Text>
                  <Select
                    style={{ flex: 1 }}
                    data={availableOptionsForIndex(index)}
                    value={yardId || null}
                    onChange={(value) => value && setMilestone(index, value)}
                    placeholder="Select yard"
                    searchable
                  />
                  <ActionIcon
                    variant="subtle"
                    color="red"
                    disabled={form.milestones.length <= 2}
                    onClick={() => removeMilestone(index)}
                  >
                    <Trash2 size={16} />
                  </ActionIcon>
                </Group>
              );
            })}
            <Group justify="flex-end">
              <Button variant="default" type="button" onClick={resetForm}>
                Cancel
              </Button>
              <Button color="edr-green" type="submit" loading={isSaving}>
                Save
              </Button>
            </Group>
          </Stack>
        </form>
      </Modal>

      <Modal
        opened={Boolean(viewing)}
        onClose={() => setViewing(null)}
        title={<Text fw={600}>Route details</Text>}
        radius="lg"
        centered
      >
        {viewing ? (
          <Stack gap="sm">
            <div>
              <Text size="sm" fw={500}>
                Name
              </Text>
              <Text size="sm" c="dimmed">
                {viewing.name}
              </Text>
            </div>
            <div>
              <Text size="sm" fw={500}>
                Status
              </Text>
              <Text size="sm" c="dimmed">
                {viewing.isActive ? "Active" : "Inactive"}
              </Text>
            </div>
            <div>
              <Text size="sm" fw={500}>
                Stops
              </Text>
              <Stack gap={6} mt={6}>
                {routeStops(viewing).map((stop, index, stops) => (
                  <Text key={`${stop}-${index}`} size="sm" c="dimmed">
                    {index === 0
                      ? "Origin"
                      : index === stops.length - 1
                        ? "Destination"
                        : `Milestone ${index}`}
                    : {stop}
                  </Text>
                ))}
              </Stack>
            </div>
          </Stack>
        ) : null}
      </Modal>
    </PageContainer>
  );
}
