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

import { PageContainer, PageHeader } from "@/components/page";
import ManageRuleEngineOrderDialog from "@/components/ruleEngine/ManageRuleEngineOrderDialog";
import RuleEngineCardGrid from "@/components/ruleEngine/RuleEngineCardGrid";
import RuleEngineFormDialog from "@/components/ruleEngine/RuleEngineFormDialog";
import RuleEngineOrderControls from "@/components/ruleEngine/RuleEngineOrderControls";
import RuleEngineRecordActions from "@/components/ruleEngine/RuleEngineRecordActions";
import RuleEngineToolbar from "@/components/ruleEngine/RuleEngineToolbar";
import { formatCell } from "@/components/ruleEngine/ruleEngineFormat";
import { getOrderItemLabel } from "@/components/ruleEngine/ruleEngineOrder.utils";
import { ruleEngineTable } from "@/components/ruleEngine/ruleEngineStyles";
import { useRuleEngineViewMode } from "@/components/ruleEngine/useRuleEngineViewMode";
import {
    useApprovalChain,
    useCargoLeafOptions,
    useCargoTypeParentOptions,
    useContainerTypeOptions,
    useLiveRateOptions,
    useRateWorkflow,
    useRuleEngineList,
    useRuleEngineMutations,
    useRuleEngineOrderList,
    useRuleEngineOrderMutations,
} from "@/hooks/rule-engine/useRuleEngine";
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 type { RuleEngineRecord } from "@/types/rule-engine";
import {
    DataTable,
    DataTableFooter,
    usePagination,
} 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 usesCargoTypeField = Boolean(
    config?.formFields.some((f) => f.name === "cargoTypeId"),
  );
  const usesLiveRateField = Boolean(
    config?.formFields.some((f) => f.name === "rateId"),
  );

  const { data: cargoParentOptions, isLoading: cargoParentOptionsLoading } =
    useCargoTypeParentOptions(editingId, config?.slug === "cargo-types");
  const { data: cargoLeafOptions, isLoading: cargoLeafOptionsLoading } =
    useCargoLeafOptions(usesCargoTypeField);
  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 === "cargoTypeId") {
        return {
          ...field,
          type: "select" as const,
          options: cargoLeafOptions ?? [],
        };
      }
      if (field.name === "rateId") {
        return {
          ...field,
          type: "select" as const,
          options: liveRateOptions ?? [],
        };
      }
      return field;
    });
  }, [config, cargoParentOptions, cargoLeafOptions, 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") {
      // Base-freight categories have no surcharge trigger field — the engine
      // treats them as ALWAYS. Surcharges (Applies to = Other) keep their
      // chosen trigger.
      const isSurcharge = values.appliesTo === "OTHER";
      payload = {
        ...values,
        currency: "USD",
        trigger: isSurcharge ? values.trigger : "ALWAYS",
      };
    } 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();
  const addLabel = `Add ${config.label.replace(/s$/, "")}`;

  return (
    <PageContainer>
      <PageHeader
        title={config.label}
        subtitle={config.subtitle}
        action={
          canManage ? (
            <Button leftSection={<Plus size={18} />} onClick={openCreate}>
              {addLabel}
            </Button>
          ) : undefined
        }
      />

      <Card p={0}>
        <Stack gap={0}>
          <Box px="md" pt="md" pb="sm" w="100%">
            <RuleEngineToolbar
              search={search}
              onSearchChange={
                config.supportsSearch
                  ? (v) => {
                    setSearch(v);
                    setPagination({
                      pageIndex: 0,
                      pageSize: pagination.pageSize,
                    });
                  }
                  : undefined
              }
              showSearch={Boolean(config.supportsSearch)}
              searchPlaceholder={config.searchPlaceholder}
              onManageOrder={
                canManage && config.orderConfig
                  ? () => setOrderDialogOpen(true)
                  : undefined
              }
              viewMode={viewMode}
              onViewModeChange={setViewMode}
            />
          </Box>

          {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 bg-transparent"
              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) ||
          (usesCargoTypeField && cargoLeafOptionsLoading) ||
          (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"
              loading={remove.isPending}
              onClick={() => {
                if (!deleteTarget) return;
                remove.mutate(deleteTarget.id, {
                  onSuccess: () => setDeleteTarget(null),
                });
              }}
            >
              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">
              <Loader />
            </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>
    </PageContainer>
  );
};

export default RuleEngineResourcePage;
