import { useCallback, useEffect, useMemo, useState } from "react";
import { Navigate, useLocation, useParams } from "react-router-dom";
import { useAuth } from "@/auth/useAuth";
import { canAccessRuleEngineResource } from "@/lib/permissions";
import type { ColumnDef } from "@tanstack/react-table";
import { Loader2 } from "lucide-react";
import { Card, Button, Modal, Stack, Group, Text, List } from "@mantine/core";

import RuleEngineCardGrid from "@/components/ruleEngine/RuleEngineCardGrid";
import RuleEngineFormDialog from "@/components/ruleEngine/RuleEngineFormDialog";
import ManageRuleEngineOrderDialog from "@/components/ruleEngine/ManageRuleEngineOrderDialog";
import RuleEngineOrderControls from "@/components/ruleEngine/RuleEngineOrderControls";
import RuleEngineRecordActions from "@/components/ruleEngine/RuleEngineRecordActions";
import { getOrderItemLabel } from "@/components/ruleEngine/ruleEngineOrder.utils";
import RuleEngineToolbar from "@/components/ruleEngine/RuleEngineToolbar";
import { formatCell } from "@/components/ruleEngine/ruleEngineFormat";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import { useRuleEngineViewMode } from "@/components/ruleEngine/useRuleEngineViewMode";
import {
  DEFAULT_CONFIGURATION_SLUG,
  DEFAULT_RULES_SLUG,
  RULE_ENGINE_CATEGORY_BASE_PATH,
  RULE_ENGINE_SELECT_NONE,
  getRuleEngineResource,
  type RuleEngineNavCategory,
} from "@/pages/ruleEngine/config/resources";
import {
  useApprovalChain,
  useCargoTypeParentOptions,
  useContainerTypeOptions,
  useLiveRateOptions,
  useRateWorkflow,
  useRuleEngineList,
  useRuleEngineMutations,
  useRuleEngineOrderList,
  useRuleEngineOrderMutations,
} from "@/hooks/rule-engine/useRuleEngine";
import type { RuleEngineRecord } from "@/types/rule-engine";
import {
  DataTable,
  DataTableFooter,
  getCoreRowModel,
  usePagination,
  useReactTable,
} from "@edr/ui-common";

const pathCategory = (pathname: string): RuleEngineNavCategory | undefined => {
  const normalized = pathname.toLowerCase();
  if (normalized.startsWith("/dashboard/configuration")) return "configuration";
  if (normalized.startsWith("/dashboard/rules")) return "rules";
  return undefined;
};

const RuleEngineResourcePage = () => {
  const { user } = useAuth();
  const { resource: resourceSlug } = useParams<{ resource: string }>();
  const location = useLocation();
  const category = pathCategory(location.pathname);
  const config = resourceSlug ? getRuleEngineResource(resourceSlug) : undefined;

  const defaultPath = category
    ? `${RULE_ENGINE_CATEGORY_BASE_PATH[category]}/${
        category === "rules" ? DEFAULT_RULES_SLUG : DEFAULT_CONFIGURATION_SLUG
      }`
    : `${RULE_ENGINE_CATEGORY_BASE_PATH.configuration}/${DEFAULT_CONFIGURATION_SLUG}`;

  const { pagination, setPagination } = usePagination({ pageSize: 10 });
  const [search, setSearch] = useState("");
  const [formOpen, setFormOpen] = useState(false);
  const [editing, setEditing] = useState<RuleEngineRecord | null>(null);
  const [deleteTarget, setDeleteTarget] = useState<RuleEngineRecord | null>(null);
  const [chainOpen, setChainOpen] = useState(false);
  const [orderDialogOpen, setOrderDialogOpen] = useState(false);
  const { viewMode, setViewMode } = useRuleEngineViewMode(
    config?.slug ?? DEFAULT_CONFIGURATION_SLUG,
  );

  const canView = Boolean(
    config && canAccessRuleEngineResource(user, config.slug, "view"),
  );
  const canManage = Boolean(
    config && canAccessRuleEngineResource(user, config.slug, "manage"),
  );

  const listParams = useMemo(
    () => ({
      search: config?.supportsSearch ? search.trim() || undefined : undefined,
      page: pagination.pageIndex + 1,
      pageSize: pagination.pageSize,
      ...(config?.orderConfig
        ? {
            sortBy: config.orderConfig.field,
            sortOrder: "ASC" as const,
          }
        : {}),
    }),
    [
      config?.orderConfig,
      config?.supportsSearch,
      search,
      pagination.pageIndex,
      pagination.pageSize,
    ],
  );

  useEffect(() => {
    setPagination((prev) => ({ pageIndex: 0, pageSize: prev.pageSize }));
    setSearch("");
  }, [config?.slug, setPagination]);

  const { data, isLoading, isError, error } = useRuleEngineList(
    config?.slug ?? DEFAULT_CONFIGURATION_SLUG,
    listParams,
  );

  const { create, update, remove } = useRuleEngineMutations(
    config?.slug ?? DEFAULT_CONFIGURATION_SLUG,
  );
  const { reorder, moveOrder } = useRuleEngineOrderMutations(
    config?.slug ?? DEFAULT_CONFIGURATION_SLUG,
  );
  const { data: orderListData, isLoading: orderListLoading } = useRuleEngineOrderList(
    config?.slug ?? DEFAULT_CONFIGURATION_SLUG,
    Boolean(orderDialogOpen && config?.orderConfig),
    config?.orderConfig?.field,
  );
  const { submit, approve } = useRateWorkflow();
  const { data: chainData, isLoading: chainLoading } = useApprovalChain(
    chainOpen && config?.slug === "approval-rules",
  );

  const editingId = editing?.id ? String(editing.id) : undefined;
  const usesContainerTypeField = Boolean(
    config?.formFields.some((f) => f.name === "containerTypeId"),
  );
  const usesLiveRateField = Boolean(
    config?.formFields.some((f) => f.name === "rateId"),
  );

  const { data: cargoParentOptions, isLoading: cargoParentOptionsLoading } =
    useCargoTypeParentOptions(editingId, config?.slug === "cargo-types");
  const { data: containerTypeOptions, isLoading: containerTypeOptionsLoading } =
    useContainerTypeOptions(
      config?.slug === "rates",
      usesContainerTypeField,
    );
  const { data: liveRateOptions, isLoading: liveRateOptionsLoading } =
    useLiveRateOptions(usesLiveRateField);

  const formFields = useMemo(() => {
    if (!config) return [];
    return config.formFields.map((field) => {
      if (config.slug === "cargo-types" && field.name === "parentGroupId") {
        return {
          ...field,
          options:
            cargoParentOptions ?? [
              { label: "None", value: RULE_ENGINE_SELECT_NONE },
            ],
        };
      }
      if (field.name === "containerTypeId") {
        return {
          ...field,
          type: "select" as const,
          options: containerTypeOptions ?? [],
        };
      }
      if (field.name === "rateId") {
        return {
          ...field,
          type: "select" as const,
          options: liveRateOptions ?? [],
        };
      }
      return field;
    });
  }, [config, cargoParentOptions, containerTypeOptions, liveRateOptions]);

  const rows = data?.data ?? [];
  const meta = data?.meta;
  const pageCount = meta?.totalPages ?? 1;
  const totalCount = meta?.total ?? rows.length;

  const { data: createPositionList, isLoading: createPositionLoading } = useRuleEngineOrderList(
    config?.slug ?? DEFAULT_CONFIGURATION_SLUG,
    Boolean(formOpen && !editing && config?.orderConfig),
    config?.orderConfig?.field,
  );

  const createPositionOptions = useMemo(() => {
    if (!config?.orderConfig || !createPositionList?.data?.length) return undefined;
    return createPositionList.data
      .filter((row) => row.id)
      .map((row) => ({
        label: getOrderItemLabel(row, config.slug),
        value: String(row.id),
      }));
  }, [config?.orderConfig, config?.slug, createPositionList?.data]);


  const handleApproveRate = useCallback(
    (record: RuleEngineRecord) => {
      approve.mutate(String(record.id));
    },
    [approve],
  );

  const handleMoveOrder = useCallback(
    (id: string, direction: "up" | "down") => {
      moveOrder.mutate({ id, direction });
    },
    [moveOrder],
  );

  const columns = useMemo((): ColumnDef<RuleEngineRecord>[] => {
    if (!config) return [];

    const headerClassName = ruleEngineTable.headerCell;
    const cellClassName = ruleEngineTable.bodyCell;

    const base: ColumnDef<RuleEngineRecord>[] = config.columns.map((col) => ({
      id: col.id,
      header: col.header,
      meta: { headerClassName, cellClassName },
      cell: ({ row }) => formatCell(row.original[col.accessorKey], col.format),
    }));

    base.push({
      id: "actions",
      header: "Actions",
      size: config.orderConfig ? 200 : 140,
      minSize: config.orderConfig ? 180 : 120,
      meta: {
        headerClassName,
        cellClassName: `${cellClassName} whitespace-nowrap`,
      },
      cell: ({ row }) => (
        <div onClick={(e) => e.stopPropagation()} data-stop-row-click>
          <Group gap="xs" wrap="nowrap" justify="flex-end">
            {config.orderConfig && canManage ? (
              <RuleEngineOrderControls
                record={row.original}
                orderConfig={config.orderConfig}
                totalCount={totalCount}
                disabled={moveOrder.isPending}
                onMove={handleMoveOrder}
              />
            ) : null}
            <RuleEngineRecordActions
              record={row.original}
              config={config}
              layout="row"
              readOnly={!canManage}
              onEdit={(record) => {
                setEditing(record);
                setFormOpen(true);
              }}
              onDelete={setDeleteTarget}
              onViewChain={
                config.slug === "approval-rules" ? () => setChainOpen(true) : undefined
              }
              onSubmitRate={canManage ? (id) => submit.mutate(id) : undefined}
              onApproveRate={canManage ? handleApproveRate : undefined}
            />
          </Group>
        </div>
      ),
    });

    return base;
  }, [canManage, config, submit, handleApproveRate, handleMoveOrder, moveOrder.isPending, totalCount]);

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

  if (!resourceSlug || !category) {
    return <Navigate to={defaultPath} replace />;
  }

  if (!config || config.category !== category) {
    return <Navigate to={defaultPath} replace />;
  }

  if (!canView) {
    return <Navigate to="/dashboard/overview" replace />;
  }

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

  const openEdit = (record: RuleEngineRecord) => {
    setEditing(record);
    setFormOpen(true);
  };

  const handleFormSubmit = (values: Record<string, unknown>) => {
    let payload = values;
    if (config.slug === "rates") {
      payload = { ...values, currency: "USD" };
    } else if (config.slug === "priority-configs") {
      // Label is required by the backend but hidden in the UI for now.
      payload = { ...values, label: String(Date.now()) };
    }

    if (editing?.id) {
      update.mutate(
        { id: editing.id, payload },
        {
          onSuccess: () => {
            setFormOpen(false);
            setEditing(null);
          },
        },
      );
    } else {
      create.mutate(payload, {
        onSuccess: () => {
          setFormOpen(false);
          setEditing(null);
        },
      });
    }
  };

  const itemLabel = config.label.toLowerCase();

  return (
    <Stack gap="lg">
      <Card p="lg" radius="lg" withBorder style={{ background: "white", boxShadow: "0 1px 3px rgba(0, 0, 0, 0.05)" }}>
        <Stack gap="md">
          <RuleEngineToolbar
            search={search}
            onSearchChange={
              config.supportsSearch
                ? (v) => {
                    setSearch(v);
                    setPagination({ pageIndex: 0, pageSize: pagination.pageSize });
                  }
                : undefined
            }
            showSearch={Boolean(config.supportsSearch)}
            searchPlaceholder={config.searchPlaceholder}
            onAdd={canManage ? openCreate : undefined}
            addLabel={`Add ${config.label.replace(/s$/, "")}`}
            onManageOrder={
              canManage && config.orderConfig ? () => setOrderDialogOpen(true) : undefined
            }
            viewMode={viewMode}
            onViewModeChange={setViewMode}
          />

          {viewMode === "table" ? (
            <DataTable
              columns={columns}
              data={rows}
              status={tableStatus}
              error={
                isError
                  ? {
                      message: "Failed to load data",
                      description:
                        error instanceof Error ? error.message : "Unknown error",
                    }
                  : undefined
              }
              emptyMessage={`No ${itemLabel} found.`}
              pagination={{
                pageIndex: pagination.pageIndex,
                pageSize: pagination.pageSize,
                pageCount,
                totalCount,
              }}
              tableOptions={{
                manualPagination: true,
                pageCount,
                state: { pagination },
                onPaginationChange: setPagination,
              }}
              containerClassName="border-0 shadow-none [&_[data-slot=table-row]]:border-border"
              footerClassName="border-t border-border bg-card"
              footer={({ table, pagination: footerPagination }) => (
                <DataTableFooter
                  table={table}
                  pagination={footerPagination}
                  options={{
                    labels: {
                      showing: "Showing",
                      ofLabel: "of",
                      items: itemLabel,
                    },
                  }}
                />
              )}
            />
          ) : (
            <RuleEngineCardGrid
              config={config}
              rows={rows}
              status={tableStatus}
              emptyMessage={`No ${itemLabel} found.`}
              itemLabel={itemLabel}
              pagination={pagination}
              pageCount={pageCount}
              totalCount={totalCount}
              onPaginationChange={setPagination}
              readOnly={!canManage}
              onEdit={canManage ? openEdit : undefined}
              onDelete={canManage ? setDeleteTarget : undefined}
              onViewChain={
                config.slug === "approval-rules" ? () => setChainOpen(true) : undefined
              }
              onSubmitRate={canManage ? (id) => submit.mutate(id) : undefined}
              onApproveRate={canManage ? handleApproveRate : undefined}
            />
          )}
        </Stack>
      </Card>

      <RuleEngineFormDialog
        open={formOpen}
        onOpenChange={setFormOpen}
        title={editing ? `Edit ${config.label.replace(/s$/, "")}` : `Add ${config.label.replace(/s$/, "")}`}
        description={
          editing
            ? `Update this ${config.label.toLowerCase()} record.`
            : `Create a new ${config.label.toLowerCase()} record.`
        }
        fields={formFields}
        initialRecord={editing}
        isSubmitting={create.isPending || update.isPending}
        selectOptionsLoading={
          (config.slug === "cargo-types" && cargoParentOptionsLoading) ||
          (usesContainerTypeField && containerTypeOptionsLoading) ||
          (usesLiveRateField && liveRateOptionsLoading)
        }
        positionOptions={!editing ? createPositionOptions : undefined}
        positionLoading={createPositionLoading}
        onSubmit={handleFormSubmit}
      />

      {config.orderConfig ? (
        <ManageRuleEngineOrderDialog
          open={orderDialogOpen}
          onOpenChange={setOrderDialogOpen}
          config={config}
          items={orderListData?.data ?? []}
          isLoading={orderListLoading}
          isSaving={reorder.isPending}
          onSave={(payload) => {
            reorder.mutate(payload, {
              onSuccess: () => setOrderDialogOpen(false),
            });
          }}
        />
      ) : null}

      <Modal
        opened={Boolean(deleteTarget)}
        onClose={() => setDeleteTarget(null)}
        title="Delete record?"
        centered
        size="sm"
      >
        <Stack gap="md">
          <Text size="sm">
            This will soft-delete the selected {config.label.toLowerCase()} record.
          </Text>
          <Group justify="flex-end" gap="sm">
            <Button variant="default" onClick={() => setDeleteTarget(null)}>
              Cancel
            </Button>
            <Button
              color="red"
              disabled={remove.isPending}
              onClick={() => {
                if (!deleteTarget) return;
                remove.mutate(deleteTarget.id, {
                  onSuccess: () => setDeleteTarget(null),
                });
              }}
              leftSection={remove.isPending && <Loader2 size={16} />}
            >
              {remove.isPending ? "Deleting..." : "Delete"}
            </Button>
          </Group>
        </Stack>
      </Modal>

      <Modal
        opened={chainOpen}
        onClose={() => setChainOpen(false)}
        title="Approval chain"
        centered
        size="md"
      >
        <Stack gap="md">
          {chainLoading ? (
            <Group justify="center" p="xl">
              <Loader2 size={32} style={{ animation: "spin 1s linear infinite" }} />
            </Group>
          ) : (
            <>
              {(chainData ?? []).length === 0 ? (
                <Text size="sm" c="dimmed">No approval rules configured.</Text>
              ) : (
                <List spacing="md">
                  {(chainData ?? []).map((step, index) => (
                    <List.Item key={String(step.id ?? index)}>
                      <Stack gap="xs">
                        <Text size="sm" fw={500}>
                          Step {String(step.stepOrder ?? index + 1)}: {String(step.actionLabel ?? "")}
                        </Text>
                        <Text size="sm" c="dimmed">
                          Role: {String(step.requiredRole ?? "—")}
                        </Text>
                      </Stack>
                    </List.Item>
                  ))}
                </List>
              )}
            </>
          )}
        </Stack>
      </Modal>
    </Stack>
  );
};

export default RuleEngineResourcePage;
