import { useMemo, useState } from "react";
import { Navigate, useNavigate, useParams } from "react-router-dom";
import {
  Badge,
  Box,
  Breadcrumbs,
  Button,
  Card,
  Group,
  Loader,
  Modal,
  Stack,
  Text,
  TextInput,
  ThemeIcon,
  Tooltip,
  UnstyledButton,
} from "@mantine/core";
import {
  Boxes,
  ChevronRight,
  FileText,
  Home,
  Layers,
  Package,
  Pencil,
  Plus,
  Search,
  ShieldCheck,
  Trash2,
} from "lucide-react";

import { useAuth } from "@/auth/useAuth";
import { canAccessRuleEngineResource } from "@/lib/permissions";
import RuleEngineFormDialog from "@/components/ruleEngine/RuleEngineFormDialog";
import {
  getRuleEngineResource,
  RULE_ENGINE_SELECT_NONE,
  type FormFieldDef,
} from "@/pages/ruleEngine/config/resources";
import {
  useRuleEngineList,
  useRuleEngineMutations,
} from "@/hooks/rule-engine/useRuleEngine";
import type { RuleEngineRecord } from "@/types/rule-engine";

const CARGO_SLUG = "cargo-types";
const BASE_PATH = "/dashboard/configuration/cargo-types";

interface CargoNode extends RuleEngineRecord {
  cargoTypeName?: string;
  code?: string;
  parentGroupId?: string | null;
  showFreeTextBox?: boolean;
  requiresDirectorApproval?: boolean;
  /** How this cargo is measured (PER_TON / PER_ITEM); null for groups/unset. */
  unitOfMeasure?: string | null;
  isActive?: boolean;
  displayOrder?: number;
}

const str = (v: unknown): string => (v == null ? "" : String(v));
const orderOf = (n: CargoNode): number => Number(n.displayOrder ?? 0);

/** Create/edit form fields. Parent is set from the current page, never picked. */
const FORM_FIELDS: FormFieldDef[] = [
  { name: "cargoTypeName", label: "Cargo type name", type: "text", required: true },
  {
    // How this cargo is measured. Optional — leave "None" for grouping
    // categories; set it on the actual commodities so bookings ask for the
    // right amount (estimated tons vs. total item count).
    name: "unitOfMeasure",
    label: "Unit of measure",
    type: "select",
    optional: true,
    placeholder: "Select unit (optional)",
    options: [
      { label: "None", value: RULE_ENGINE_SELECT_NONE },
      { label: "Per ton (bulk)", value: "PER_TON" },
      { label: "Per item (break-bulk)", value: "PER_ITEM" },
    ],
  },
  { name: "showFreeTextBox", label: "Show free text box", type: "boolean" },
  { name: "requiresDirectorApproval", label: "Requires director approval", type: "boolean" },
  { name: "isActive", label: "Active", type: "boolean" },
];

type FormMode = { kind: "create" } | { kind: "edit"; record: CargoNode };

const CargoTypesPage = () => {
  const { user } = useAuth();
  const navigate = useNavigate();
  const { id: currentId } = useParams<{ id: string }>();
  const config = getRuleEngineResource(CARGO_SLUG);

  const canView = canAccessRuleEngineResource(user, CARGO_SLUG, "view");
  const canManage = canAccessRuleEngineResource(user, CARGO_SLUG, "manage");

  // One fetch of the whole (small) set; the tree, ancestry and each level are
  // derived client-side so drilling between levels is instant.
  const { data, isLoading, isError } = useRuleEngineList(CARGO_SLUG, {
    page: 1,
    pageSize: 500,
    sortBy: "displayOrder",
    sortOrder: "ASC",
  });

  const { create, update, remove } = useRuleEngineMutations(CARGO_SLUG);

  const [search, setSearch] = useState("");
  const [formMode, setFormMode] = useState<FormMode | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<CargoNode | null>(null);

  const all = (data?.data ?? []) as CargoNode[];

  const { byId, childrenOf } = useMemo(() => {
    const byId = new Map<string, CargoNode>(all.map((n) => [n.id, n]));
    const childrenOf = new Map<string, CargoNode[]>();
    for (const node of all) {
      const parentId = node.parentGroupId && byId.has(node.parentGroupId) ? node.parentGroupId : "";
      const key = parentId || "__root__";
      const list = childrenOf.get(key) ?? [];
      list.push(node);
      childrenOf.set(key, list);
    }
    for (const list of childrenOf.values()) {
      list.sort(
        (a, b) =>
          orderOf(a) - orderOf(b) ||
          str(a.cargoTypeName).localeCompare(str(b.cargoTypeName)),
      );
    }
    return { byId, childrenOf };
  }, [all]);

  // Current node (null at root) and its ancestor chain for the breadcrumb.
  const current = currentId ? byId.get(currentId) ?? null : null;
  const ancestors = useMemo(() => {
    const chain: CargoNode[] = [];
    let node = current;
    const seen = new Set<string>();
    while (node && !seen.has(node.id)) {
      chain.unshift(node);
      seen.add(node.id);
      node = node.parentGroupId ? byId.get(node.parentGroupId) ?? null : null;
    }
    return chain;
  }, [current, byId]);

  const levelKey = current ? current.id : "__root__";
  const levelNodes = childrenOf.get(levelKey) ?? [];

  const term = search.trim().toLowerCase();
  const matches = (n: CargoNode) =>
    !term ||
    str(n.cargoTypeName).toLowerCase().includes(term) ||
    str(n.code).toLowerCase().includes(term);
  const visibleNodes = useMemo(
    () => (term ? levelNodes.filter(matches) : levelNodes),
    [levelNodes, term],
  );

  if (!config) return <Navigate to="/dashboard/overview" replace />;
  if (!canView) return <Navigate to="/dashboard/overview" replace />;
  // A bad/stale :id (after data loads) → fall back to the root list.
  if (!isLoading && currentId && !current) return <Navigate to={BASE_PATH} replace />;

  const atRoot = !current;
  const countAtRoot = (childrenOf.get("__root__") ?? []).length;

  const handleSubmit = (values: Record<string, unknown>) => {
    const payload: Record<string, unknown> = { ...values };
    // Add always attaches to the page we're on; edit keeps the node's parent.
    if (formMode?.kind === "create" && current) {
      payload.parentGroupId = current.id;
    }
    const done = () => setFormMode(null);
    if (formMode?.kind === "edit") {
      update.mutate({ id: formMode.record.id, payload }, { onSuccess: done });
    } else {
      create.mutate(payload, { onSuccess: done });
    }
  };

  const addLabel = atRoot ? "Add category" : "Add cargo type";

  return (
    <Stack gap="lg">
      {/* ── Header ─────────────────────────────────────────────── */}
      <Card
        p="lg"
        radius="lg"
        withBorder
        style={{ background: "white", boxShadow: "0 1px 3px rgba(0,0,0,0.05)" }}
      >
        {/* Breadcrumb */}
        <Breadcrumbs
          separator={<ChevronRight size={14} style={{ color: "var(--mantine-color-gray-5)" }} />}
          mb="md"
        >
          <UnstyledButton onClick={() => navigate(BASE_PATH)}>
            <Group gap={5} wrap="nowrap">
              <Home size={14} style={{ color: "var(--mantine-color-teal-7)" }} />
              <Text fz={13} fw={600} c={atRoot ? "dark.7" : "teal.7"}>
                Cargo Types
              </Text>
            </Group>
          </UnstyledButton>
          {ancestors.map((node, i) => {
            const isLast = i === ancestors.length - 1;
            return (
              <UnstyledButton
                key={node.id}
                onClick={() => !isLast && navigate(`${BASE_PATH}/${node.id}`)}
                style={{ cursor: isLast ? "default" : "pointer" }}
              >
                <Text fz={13} fw={isLast ? 700 : 600} c={isLast ? "dark.7" : "teal.7"} truncate maw={220}>
                  {str(node.cargoTypeName) || "Untitled"}
                </Text>
              </UnstyledButton>
            );
          })}
        </Breadcrumbs>

        <Group justify="space-between" align="flex-start" wrap="wrap" gap="md">
          <Group gap="md" wrap="nowrap" style={{ minWidth: 0 }}>
            <ThemeIcon size={48} radius="md" variant="light" color="teal">
              {atRoot ? <Boxes size={26} /> : <Layers size={26} />}
            </ThemeIcon>
            <Box style={{ minWidth: 0 }}>
              <Group gap={8} wrap="nowrap">
                <Text fw={800} fz={22} c="dark.8" truncate>
                  {atRoot ? "Cargo Types" : str(current?.cargoTypeName) || "Untitled"}
                </Text>
                {!atRoot && current?.code ? (
                  <Badge variant="default" radius="sm">
                    {str(current.code)}
                  </Badge>
                ) : null}
                {!atRoot && current?.isActive === false ? (
                  <Badge variant="light" color="gray" radius="sm">
                    Inactive
                  </Badge>
                ) : null}
              </Group>
              <Text fz={13} c="dimmed" mt={2}>
                {atRoot
                  ? `${countAtRoot} top-level categor${countAtRoot === 1 ? "y" : "ies"} — click one to see what's inside`
                  : `${levelNodes.length} cargo type${levelNodes.length === 1 ? "" : "s"} directly under this category`}
              </Text>
            </Box>
          </Group>

          <Group gap="sm" wrap="nowrap">
            <TextInput
              value={search}
              onChange={(e) => setSearch(e.currentTarget.value)}
              placeholder="Search this level…"
              leftSection={<Search size={16} />}
              w={240}
            />
            {canManage && (
              <Button
                color="teal"
                leftSection={<Plus size={16} />}
                onClick={() => setFormMode({ kind: "create" })}
              >
                {addLabel}
              </Button>
            )}
          </Group>
        </Group>
      </Card>

      {/* ── Level list ─────────────────────────────────────────── */}
      <Card
        p={0}
        radius="lg"
        withBorder
        style={{
          background: "white",
          boxShadow: "0 1px 3px rgba(0,0,0,0.05)",
          overflow: "hidden",
        }}
      >
        {isLoading ? (
          <Group justify="center" p="xl">
            <Loader color="teal" />
          </Group>
        ) : isError ? (
          <Text p="xl" c="red" ta="center">
            Failed to load cargo types.
          </Text>
        ) : visibleNodes.length === 0 ? (
          <Stack align="center" gap="sm" py={56}>
            <ThemeIcon size={52} radius="xl" variant="light" color="gray">
              <Package size={26} />
            </ThemeIcon>
            <Text fw={600} c="dark.6">
              {term
                ? "Nothing matches your search"
                : atRoot
                  ? "No cargo categories yet"
                  : `No cargo types under “${str(current?.cargoTypeName)}” yet`}
            </Text>
            {!term && canManage && (
              <Button
                variant="light"
                color="teal"
                leftSection={<Plus size={16} />}
                onClick={() => setFormMode({ kind: "create" })}
              >
                {atRoot ? "Add your first category" : "Add the first cargo type"}
              </Button>
            )}
          </Stack>
        ) : (
          <Stack gap={0}>
            {visibleNodes.map((node, i) => (
              <CargoRow
                key={node.id}
                node={node}
                childCount={(childrenOf.get(node.id) ?? []).length}
                topBorder={i > 0}
                canManage={canManage}
                onOpen={() => navigate(`${BASE_PATH}/${node.id}`)}
                onEdit={() => setFormMode({ kind: "edit", record: node })}
                onDelete={() => setDeleteTarget(node)}
              />
            ))}
          </Stack>
        )}
      </Card>

      {/* ── Create / edit dialog ───────────────────────────────── */}
      <RuleEngineFormDialog
        open={Boolean(formMode)}
        onOpenChange={(open) => {
          if (!open) setFormMode(null);
        }}
        title={
          formMode?.kind === "edit"
            ? `Edit ${str(formMode.record.cargoTypeName)}`
            : atRoot
              ? "Add category"
              : `Add cargo under “${str(current?.cargoTypeName)}”`
        }
        description={
          formMode?.kind === "edit"
            ? "Update this cargo type."
            : atRoot
              ? "Create a top-level cargo category."
              : "Create a cargo type inside this category. It's attached here automatically."
        }
        fields={FORM_FIELDS}
        initialRecord={formMode?.kind === "edit" ? formMode.record : null}
        isSubmitting={create.isPending || update.isPending}
        onSubmit={handleSubmit}
      />

      {/* ── Delete confirm ─────────────────────────────────────── */}
      <Modal
        opened={Boolean(deleteTarget)}
        onClose={() => setDeleteTarget(null)}
        title="Delete cargo type?"
        centered
        size="sm"
      >
        <Stack gap="md">
          <Text size="sm">
            {deleteTarget && (childrenOf.get(deleteTarget.id)?.length ?? 0) > 0 ? (
              <>
                <Text span fw={600}>
                  {str(deleteTarget?.cargoTypeName)}
                </Text>{" "}
                has {childrenOf.get(deleteTarget!.id)?.length} cargo type(s) under it. Deleting it
                leaves them without a category. Continue?
              </>
            ) : (
              <>
                This will delete{" "}
                <Text span fw={600}>
                  {str(deleteTarget?.cargoTypeName)}
                </Text>
                .
              </>
            )}
          </Text>
          <Group justify="flex-end" gap="sm">
            <Button variant="default" onClick={() => setDeleteTarget(null)}>
              Cancel
            </Button>
            <Button
              color="red"
              loading={remove.isPending}
              onClick={() => {
                if (!deleteTarget) return;
                remove.mutate(deleteTarget.id, { onSuccess: () => setDeleteTarget(null) });
              }}
            >
              Delete
            </Button>
          </Group>
        </Stack>
      </Modal>
    </Stack>
  );
};

// ── A single cargo row — drills into its own page on click ──────────────────
interface CargoRowProps {
  node: CargoNode;
  childCount: number;
  topBorder: boolean;
  canManage: boolean;
  onOpen: () => void;
  onEdit: () => void;
  onDelete: () => void;
}

function CargoRow({
  node,
  childCount,
  topBorder,
  canManage,
  onOpen,
  onEdit,
  onDelete,
}: CargoRowProps) {
  const inactive = node.isActive === false;
  const hasChildren = childCount > 0;
  return (
    <Group
      justify="space-between"
      wrap="nowrap"
      px="lg"
      py="md"
      style={{
        borderTop: topBorder ? "1px solid var(--mantine-color-gray-2)" : undefined,
        transition: "background 120ms ease",
      }}
      onMouseEnter={(e) => {
        e.currentTarget.style.background = "var(--mantine-color-teal-0)";
      }}
      onMouseLeave={(e) => {
        e.currentTarget.style.background = "";
      }}
    >
      <UnstyledButton onClick={onOpen} style={{ flex: 1, minWidth: 0 }}>
        <Group gap="sm" wrap="nowrap">
          <ThemeIcon size={36} radius="md" variant="light" color={inactive ? "gray" : "teal"}>
            {hasChildren ? <Layers size={18} /> : <Package size={18} />}
          </ThemeIcon>
          <Box style={{ minWidth: 0 }}>
            <Group gap={8} wrap="nowrap">
              <Text fw={650} fz={15} c="dark.8" truncate>
                {str(node.cargoTypeName) || "Untitled"}
              </Text>
              {node.code ? (
                <Badge size="xs" variant="default" radius="sm">
                  {str(node.code)}
                </Badge>
              ) : null}
              {node.requiresDirectorApproval ? (
                <Tooltip label="Requires director approval" withArrow>
                  <Badge
                    size="xs"
                    variant="light"
                    color="orange"
                    radius="sm"
                    leftSection={<ShieldCheck size={11} />}
                  >
                    Approval
                  </Badge>
                </Tooltip>
              ) : null}
              {node.showFreeTextBox ? (
                <Tooltip label="Shows a free-text box on booking" withArrow>
                  <Badge
                    size="xs"
                    variant="light"
                    color="blue"
                    radius="sm"
                    leftSection={<FileText size={11} />}
                  >
                    Free text
                  </Badge>
                </Tooltip>
              ) : null}
              {node.unitOfMeasure ? (
                <Tooltip label="How bookings measure this cargo" withArrow>
                  <Badge size="xs" variant="light" color="teal" radius="sm">
                    {node.unitOfMeasure === "PER_ITEM" ? "Per item" : "Per ton"}
                  </Badge>
                </Tooltip>
              ) : null}
              {inactive ? (
                <Badge size="xs" variant="light" color="gray" radius="sm">
                  Inactive
                </Badge>
              ) : null}
            </Group>
            <Text fz={12.5} c="dimmed" mt={2}>
              {hasChildren
                ? `${childCount} cargo type${childCount === 1 ? "" : "s"} inside`
                : "No cargo types inside yet — open to add"}
            </Text>
          </Box>
        </Group>
      </UnstyledButton>

      <Group gap={4} wrap="nowrap">
        {canManage && (
          <>
            <Tooltip label="Edit" withArrow>
              <Button size="compact-sm" variant="subtle" color="gray" onClick={onEdit} px={8}>
                <Pencil size={15} />
              </Button>
            </Tooltip>
            <Tooltip label="Delete" withArrow>
              <Button size="compact-sm" variant="subtle" color="red" onClick={onDelete} px={8}>
                <Trash2 size={15} />
              </Button>
            </Tooltip>
          </>
        )}
        <Tooltip label="Open" withArrow>
          <Button size="compact-sm" variant="subtle" color="teal" onClick={onOpen} px={8}>
            <ChevronRight size={18} />
          </Button>
        </Tooltip>
      </Group>
    </Group>
  );
}

export default CargoTypesPage;
