import { useEffect, useMemo, useState, type ReactNode } from "react";
import { createPortal } from "react-dom";
import {
  DragDropContext,
  Draggable,
  Droppable,
  type DraggableProvided,
  type DraggableStateSnapshot,
  type DropResult,
} from "@hello-pangea/dnd";
import { GripVertical, Loader2 } from "lucide-react";
import {
  Badge,
  Box,
  Button,
  Group,
  Modal,
  Stack,
  Tabs,
  Text,
  TextInput,
} from "@mantine/core";

import type { RuleEngineResourceConfig } from "@/pages/ruleEngine/config/resources";
import type { RuleEngineRecord } from "@/types/rule-engine";

import { getOrderItemLabel, getOrderValue } from "./ruleEngineOrder.utils";

interface OrderDraftItem {
  id: string;
  label: string;
  code?: string;
  order: number;
}

export interface ManageRuleEngineOrderDialogProps {
  open: boolean;
  onOpenChange: (open: boolean) => void;
  config: RuleEngineResourceConfig;
  items: RuleEngineRecord[];
  isLoading: boolean;
  isSaving: boolean;
  onSave: (payload: { ids: string[]; requiresDirectorApproval?: boolean }) => void;
}

const toDraftItems = (
  rows: RuleEngineRecord[],
  config: RuleEngineResourceConfig,
): OrderDraftItem[] => {
  const field = config.orderConfig!.field;
  return [...rows]
    .sort((a, b) => getOrderValue(a, field) - getOrderValue(b, field))
    .map((row) => ({
      id: String(row.id),
      label: getOrderItemLabel(row, config.slug),
      code: row.code ? String(row.code) : undefined,
      order: getOrderValue(row, field),
    }));
};

/** Reparent dragged row to body — fixes position:fixed inside Modal transforms. */
const PortalAwareRow = ({
  snapshot,
  children,
}: {
  snapshot: DraggableStateSnapshot;
  children: ReactNode;
}) => {
  if (snapshot.isDragging) {
    return createPortal(children, document.body);
  }
  return <>{children}</>;
};

const OrderRow = ({
  item,
  index,
  dragProvided,
  snapshot,
}: {
  item: OrderDraftItem;
  index: number;
  dragProvided: DraggableProvided;
  snapshot: DraggableStateSnapshot;
}) => (
  <PortalAwareRow snapshot={snapshot}>
    <Group
      ref={dragProvided.innerRef}
      {...dragProvided.draggableProps}
      {...dragProvided.dragHandleProps}
      gap="sm"
      wrap="nowrap"
      p="sm"
      style={{
        ...dragProvided.draggableProps.style,
        border: "1px solid var(--mantine-color-gray-3)",
        borderRadius: "var(--mantine-radius-md)",
        background: snapshot.isDragging ? "var(--mantine-color-gray-0)" : "white",
        boxShadow: snapshot.isDragging ? "0 8px 24px rgba(0, 0, 0, 0.12)" : undefined,
        cursor: snapshot.isDragging ? "grabbing" : "grab",
        userSelect: "none",
      }}
    >
      <Box c="dimmed" style={{ display: "flex", alignItems: "center" }}>
        <GripVertical size={18} />
      </Box>
      <Badge variant="light" color="gray" size="sm">
        {index + 1}
      </Badge>
      <Stack gap={2} style={{ flex: 1, minWidth: 0 }}>
        <Text size="sm" fw={500} truncate>
          {item.label}
        </Text>
        {item.code ? (
          <Text size="xs" c="dimmed" truncate>
            {item.code}
          </Text>
        ) : null}
      </Stack>
    </Group>
  </PortalAwareRow>
);

const ManageRuleEngineOrderDialog = ({
  open,
  onOpenChange,
  config,
  items,
  isLoading,
  isSaving,
  onSave,
}: ManageRuleEngineOrderDialogProps) => {
  const isScoped = config.orderConfig?.scopeField === "requiresDirectorApproval";
  const [tab, setTab] = useState<"standard" | "director">("standard");
  const [filter, setFilter] = useState("");
  const [standardItems, setStandardItems] = useState<OrderDraftItem[]>([]);
  const [directorItems, setDirectorItems] = useState<OrderDraftItem[]>([]);

  useEffect(() => {
    if (!open) return;
    if (isScoped) {
      setStandardItems(
        toDraftItems(
          items.filter((row) => !row.requiresDirectorApproval),
          config,
        ),
      );
      setDirectorItems(
        toDraftItems(
          items.filter((row) => row.requiresDirectorApproval),
          config,
        ),
      );
    } else {
      setStandardItems(toDraftItems(items, config));
    }
    setFilter("");
  }, [open, items, config, isScoped]);

  const activeItems = isScoped
    ? tab === "director"
      ? directorItems
      : standardItems
    : standardItems;

  const setActiveItems = isScoped
    ? tab === "director"
      ? setDirectorItems
      : setStandardItems
    : setStandardItems;

  const filteredItems = useMemo(() => {
    const q = filter.trim().toLowerCase();
    if (!q) return activeItems;
    return activeItems.filter(
      (item) =>
        item.label.toLowerCase().includes(q) ||
        (item.code?.toLowerCase().includes(q) ?? false),
    );
  }, [activeItems, filter]);

  const droppableId = isScoped
    ? `rule-engine-order-${tab}`
    : "rule-engine-order-list";

  const onDragEnd = (result: DropResult) => {
    if (!result.destination || filter.trim()) return;
    const sourceIndex = result.source.index;
    const destIndex = result.destination.index;
    if (sourceIndex === destIndex) return;

    setActiveItems((prev) => {
      const next = [...prev];
      const [removed] = next.splice(sourceIndex, 1);
      next.splice(destIndex, 0, removed!);
      return next.map((item, index) => ({ ...item, order: index + 1 }));
    });
  };

  const handleSave = () => {
    if (isScoped) {
      onSave({
        ids: (tab === "director" ? directorItems : standardItems).map((item) => item.id),
        requiresDirectorApproval: tab === "director",
      });
      return;
    }
    onSave({ ids: standardItems.map((item) => item.id) });
  };

  const renderList = (listItems: OrderDraftItem[]) => (
    <Droppable droppableId={droppableId}>
      {(provided) => (
        <Stack
          gap="xs"
          ref={provided.innerRef}
          {...provided.droppableProps}
          style={{ minHeight: 120 }}
        >
          {listItems.length === 0 ? (
            <Text size="sm" c="dimmed" ta="center" py="xl">
              No items to reorder.
            </Text>
          ) : (
            listItems.map((item, index) => (
              <Draggable
                key={item.id}
                draggableId={item.id}
                index={index}
                isDragDisabled={Boolean(filter.trim())}
              >
                {(dragProvided, snapshot) => (
                  <OrderRow
                    item={item}
                    index={index}
                    dragProvided={dragProvided}
                    snapshot={snapshot}
                  />
                )}
              </Draggable>
            ))
          )}
          {provided.placeholder}
        </Stack>
      )}
    </Droppable>
  );

  return (
    <Modal
      opened={open}
      onClose={() => onOpenChange(false)}
      title={`Manage order · ${config.label}`}
      centered
      size="lg"
      radius="lg"
      transitionProps={{ duration: 0, transition: "fade" }}
      styles={{
        content: {
          transform: "none",
          overflow: "visible",
        },
        body: {
          overflow: "visible",
        },
      }}
    >
      <DragDropContext onDragEnd={onDragEnd}>
        <Stack gap="md">
          <Text size="sm" c="dimmed">
            Drag items anywhere in the list to set display order. Changes apply when you save.
          </Text>

          {isLoading ? (
            <Group justify="center" py="xl">
              <Loader2 size={28} style={{ animation: "spin 1s linear infinite" }} />
            </Group>
          ) : isScoped ? (
            <Tabs
              value={tab}
              onChange={(value) => setTab((value as "standard" | "director") ?? "standard")}
            >
              <Tabs.List>
                <Tabs.Tab value="standard">Standard chain ({standardItems.length})</Tabs.Tab>
                <Tabs.Tab value="director">Director chain ({directorItems.length})</Tabs.Tab>
              </Tabs.List>
              <Tabs.Panel value="standard" pt="md">
                <Stack gap="md">
                  <TextInput
                    placeholder="Filter items…"
                    value={filter}
                    onChange={(e) => setFilter(e.currentTarget.value)}
                  />
                  <Box style={{ maxHeight: "50vh", overflowY: "auto", paddingRight: 4 }}>
                    {renderList(filteredItems)}
                  </Box>
                </Stack>
              </Tabs.Panel>
              <Tabs.Panel value="director" pt="md">
                <Stack gap="md">
                  <TextInput
                    placeholder="Filter items…"
                    value={filter}
                    onChange={(e) => setFilter(e.currentTarget.value)}
                  />
                  <Box style={{ maxHeight: "50vh", overflowY: "auto", paddingRight: 4 }}>
                    {renderList(filteredItems)}
                  </Box>
                </Stack>
              </Tabs.Panel>
            </Tabs>
          ) : (
            <>
              <TextInput
                placeholder="Filter items…"
                value={filter}
                onChange={(e) => setFilter(e.currentTarget.value)}
              />
              <Box style={{ maxHeight: "50vh", overflowY: "auto", paddingRight: 4 }}>
                {renderList(filteredItems)}
              </Box>
            </>
          )}

          {filter.trim() ? (
            <Text size="xs" c="dimmed">
              Clear the filter to drag and reorder items.
            </Text>
          ) : null}

          <Group justify="flex-end" gap="sm">
            <Button variant="default" onClick={() => onOpenChange(false)} disabled={isSaving}>
              Cancel
            </Button>
            <Button
              color="edr-green"
              onClick={handleSave}
              disabled={isLoading || isSaving}
              leftSection={
                isSaving ? (
                  <Loader2 size={16} style={{ animation: "spin 1s linear infinite" }} />
                ) : undefined
              }
            >
              {isSaving ? "Saving…" : "Save order"}
            </Button>
          </Group>
        </Stack>
      </DragDropContext>
    </Modal>
  );
};

export default ManageRuleEngineOrderDialog;
