import { useMemo, useState } from "react";
import { Form, useActionData, useLoaderData } from "react-router";
import {
  AppProvider as PolarisAppProvider,
  Autocomplete,
  Banner,
  BlockStack,
  Box,
  Button,
  Card,
  Checkbox,
  InlineGrid,
  InlineStack,
  Page,
  Text,
  TextField,
} from "@shopify/polaris";
import enTranslations from "@shopify/polaris/locales/en.json";
import { authenticate } from "../shopify.server";
import {
  getThresholdGiftSettings,
  listThresholdGiftRules,
  replaceThresholdGiftRules,
  saveThresholdGiftSettings,
} from "../models.threshold-gift-rules.server";

const PRODUCTS_QUERY = `#graphql
  query ThresholdGiftProducts($first: Int!) {
    products(first: $first) {
      edges {
        node {
          id
          title
          variants(first: 50) {
            edges {
              node {
                id
                title
              }
            }
          }
        }
      }
    }
  }
`;

function createEmptyRow() {
  return {
    thresholdAmount: "",
    giftVariantId: "",
    giftSearchValue: "",
    giftQuantity: "1",
  };
}

function buildVariantOptions(products) {
  return products.flatMap((product) =>
    product.variants.map((variant) => ({
      value: variant.id,
      label:
        variant.title === "Default Title"
          ? product.title
          : `${product.title} / ${variant.title}`,
    })),
  );
}

export const loader = async ({ request }) => {
  const { session, admin } = await authenticate.admin(request);
  const [settings, rules, response] = await Promise.all([
    getThresholdGiftSettings(session.shop),
    listThresholdGiftRules(session.shop),
    admin.graphql(PRODUCTS_QUERY, {
      variables: { first: 100 },
    }),
  ]);
  const json = await response.json();
  const products =
    json?.data?.products?.edges?.map(({ node }) => ({
      id: node.id,
      title: node.title,
      variants:
        node.variants?.edges?.map(({ node: variant }) => ({
          id: variant.id,
          title: variant.title,
        })) ?? [],
    })) ?? [];
  const variantOptions = buildVariantOptions(products);

  return {
    enabled: settings.enabled ?? true,
    products,
    rules: rules.length
      ? rules.map((rule) => ({
          thresholdAmount: String(rule.thresholdAmount),
          giftVariantId: rule.giftVariantId,
          giftQuantity: String(rule.giftQuantity ?? 1),
          giftSearchValue:
            variantOptions.find((option) => option.value === rule.giftVariantId)
              ?.label ?? "",
        }))
      : [createEmptyRow()],
  };
};

export const action = async ({ request }) => {
  const { session } = await authenticate.admin(request);
  const formData = await request.formData();
  const rulesJson = formData.get("rulesJson");
  const enabled = formData.get("enabled") === "true";

  if (!enabled) {
    await saveThresholdGiftSettings(session.shop, { enabled });

    return {
      status: "success",
      message: "Threshold gift rules disabled successfully.",
    };
  }

  if (!rulesJson) {
    return { status: "error", message: "No threshold rules were submitted." };
  }

  let payload;
  try {
    payload = JSON.parse(rulesJson.toString());
  } catch {
    return { status: "error", message: "Rules payload is not valid JSON." };
  }

  if (!Array.isArray(payload)) {
    return { status: "error", message: "Rules payload must be an array." };
  }

  try {
    const rules = payload.flatMap((rule, index) => {
      const thresholdAmount = Number(rule?.thresholdAmount);
      const giftVariantId =
        typeof rule?.giftVariantId === "string"
          ? rule.giftVariantId.trim()
          : "";
      const giftQuantity = Number(rule?.giftQuantity);

      if (!giftVariantId && !Number.isFinite(thresholdAmount)) return [];

      if (
        !giftVariantId ||
        !Number.isFinite(thresholdAmount) ||
        thresholdAmount <= 0 ||
        !Number.isFinite(giftQuantity) ||
        giftQuantity <= 0
      ) {
        throw new Error(
          `Rule ${index + 1} requires a threshold amount greater than 0, one gift variant, and a gift quantity greater than 0.`,
        );
      }

      return [
        {
          thresholdAmount,
          giftVariantId,
          giftQuantity: Math.trunc(giftQuantity),
        },
      ];
    });

    await replaceThresholdGiftRules(session.shop, rules, { enabled });

    return {
      status: "success",
      message: "Threshold gift rules saved successfully.",
    };
  } catch (error) {
    return {
      status: "error",
      message:
        error instanceof Error
          ? error.message
          : "Unable to save threshold gift rules.",
    };
  }
};

export default function ThresholdGiftRulesPage() {
  const { enabled, products, rules } = useLoaderData();
  const actionData = useActionData();
  const [rows, setRows] = useState(rules);
  const [rulesEnabled, setRulesEnabled] = useState(enabled);

  const variantOptions = useMemo(() => buildVariantOptions(products), [products]);

  const updateRow = (index, updates) => {
    setRows((currentRows) =>
      currentRows.map((row, rowIndex) =>
        rowIndex === index ? { ...row, ...updates } : row,
      ),
    );
  };

  const addRow = () => {
    setRows((currentRows) => [...currentRows, createEmptyRow()]);
  };

  const removeRow = (index) => {
    setRows((currentRows) =>
      currentRows.length === 1
        ? [createEmptyRow()]
        : currentRows.filter((_, rowIndex) => rowIndex !== index),
    );
  };

  const getFilteredVariantOptions = (searchValue) => {
    const normalizedSearch = searchValue.trim().toLowerCase();
    if (!normalizedSearch) return variantOptions;

    return variantOptions.filter((option) =>
      option.label.toLowerCase().includes(normalizedSearch),
    );
  };

  const getVariantLabel = (variantId) =>
    variantOptions.find((option) => option.value === variantId)?.label ??
    variantId;

  return (
    <PolarisAppProvider i18n={enTranslations}>
      <Page
        title="Threshold Gift Rules"
        subtitle="Automatically add free gift variants when the checkout cart amount is greater than a configured threshold."
        primaryAction={
          rulesEnabled
            ? { content: "Add threshold rule", onAction: addRow }
            : undefined
        }
      >
        <BlockStack gap="500">
          {actionData?.message ? (
            <Banner
              tone={actionData.status === "success" ? "success" : "critical"}
            >
              <p>{actionData.message}</p>
            </Banner>
          ) : null}

          <Card>
            <BlockStack gap="400">
              <Text as="h2" variant="headingMd">
                Threshold rules
              </Text>
              <Text as="p" tone="subdued">
                Each matching rule adds the configured gift quantity. The
                checkout extension marks those lines with line item property
                `_threshold_gift: free`.
              </Text>

              <Form method="post">
                <input
                  type="hidden"
                  name="enabled"
                  value={rulesEnabled ? "true" : "false"}
                />
                <input
                  type="hidden"
                  name="rulesJson"
                  value={JSON.stringify(rows)}
                />
                <BlockStack gap="300">
                  <Checkbox
                    label="Enable threshold gift rules on checkout"
                    helpText="When disabled, saved threshold rules stay in admin but checkout will not auto-add threshold gifts."
                    checked={rulesEnabled}
                    onChange={setRulesEnabled}
                  />

                  {rulesEnabled ? (
                    rows.map((row, index) => (
                      <Card
                        key={`threshold-rule-${index}`}
                        background="bg-surface-secondary"
                      >
                        <BlockStack gap="300">
                          <InlineGrid
                            columns={{ xs: 1, md: "180px 1fr 160px auto" }}
                            gap="300"
                          >
                            <TextField
                              label="Threshold amount"
                              type="number"
                              min={0}
                              step={0.01}
                              autoComplete="off"
                              value={row.thresholdAmount}
                              onChange={(value) =>
                                updateRow(index, { thresholdAmount: value })
                              }
                            />

                            <Autocomplete
                              options={getFilteredVariantOptions(
                                row.giftSearchValue,
                              )}
                              selected={
                                row.giftVariantId ? [row.giftVariantId] : []
                              }
                              onSelect={(selected) => {
                                const giftVariantId = selected[0] ?? "";
                                updateRow(index, {
                                  giftVariantId,
                                  giftSearchValue:
                                    getVariantLabel(giftVariantId),
                                });
                              }}
                              textField={
                                <Autocomplete.TextField
                                  label="Gift variant"
                                  value={row.giftSearchValue}
                                  autoComplete="off"
                                  placeholder="Search gift variant"
                                  onChange={(value) =>
                                    updateRow(index, {
                                      giftSearchValue: value,
                                    })
                                  }
                                />
                              }
                            />

                            <TextField
                              label="Gift quantity"
                              type="number"
                              min={1}
                              step={1}
                              autoComplete="off"
                              value={row.giftQuantity ?? "1"}
                              onChange={(value) =>
                                updateRow(index, { giftQuantity: value })
                              }
                            />

                            <Box paddingBlockStart={{ xs: "400", md: "600" }}>
                              <Button
                                tone="critical"
                                variant="tertiary"
                                onClick={() => removeRow(index)}
                              >
                                Remove
                              </Button>
                            </Box>
                          </InlineGrid>
                        </BlockStack>
                      </Card>
                    ))
                  ) : (
                    <Banner tone="info">
                      <p>
                        Threshold gift rules are disabled. Enable the checkbox
                        to view and edit saved rules.
                      </p>
                    </Banner>
                  )}

                  <InlineStack gap="300">
                    <Button submit variant="primary">
                      Save rules
                    </Button>
                    {rulesEnabled ? (
                      <Button onClick={addRow}>Add another threshold</Button>
                    ) : null}
                  </InlineStack>
                </BlockStack>
              </Form>
            </BlockStack>
          </Card>

          {rulesEnabled ? (
            <Card>
              <BlockStack gap="300">
                <Text as="h2" variant="headingMd">
                  Current rules preview
                </Text>
                <Box
                  as="pre"
                  padding="400"
                  background="bg-surface-secondary"
                  borderRadius="200"
                  overflowX="auto"
                >
                  {JSON.stringify(
                    {
                      enabled: rulesEnabled,
                      rules: rows.map((row) => ({
                        thresholdAmount: Number(row.thresholdAmount) || 0,
                        giftVariantId: row.giftVariantId,
                        giftQuantity: Number(row.giftQuantity) || 1,
                      })),
                    },
                    null,
                    2,
                  )}
                </Box>
              </BlockStack>
            </Card>
          ) : null}
        </BlockStack>
      </Page>
    </PolarisAppProvider>
  );
}
