import { ActionPanel, Button, Dialog, useNavigate } from "@tailor-platform/app-shell";
import {
  Pencil,
  Play,
  Pause,
  RotateCcw,
  Trash2,
  Sparkles,
  FolderPlus,
  Tags,
  X,
} from "lucide-react";
import { useState } from "react";
import { useMutation, useQuery } from "urql";
import { graphql, type FragmentOf, readFragment } from "@/graphql";
import { useToast } from "@/hooks/use-toast";

const ActivateProductMutation = graphql(`
  mutation ActivateProduct($id: ID!) {
    activateProduct(id: $id) {
      id
      status
    }
  }
`);

const DeactivateProductMutation = graphql(`
  mutation DeactivateProduct($id: ID!) {
    deactivateProduct(id: $id) {
      id
      status
    }
  }
`);

const ReactivateProductMutation = graphql(`
  mutation ReactivateProduct($id: ID!) {
    reactivateProduct(id: $id) {
      id
      status
    }
  }
`);

const DeleteProductMutation = graphql(`
  mutation DeleteProduct($id: ID!) {
    deleteProduct(id: $id) {
      id
    }
  }
`);

const GenerateVariantsMutation = graphql(`
  mutation GenerateVariants($productId: ID!) {
    generateVariants(productId: $productId) {
      generatedCount
    }
  }
`);

const UpdateProductCategoriesMutation = graphql(`
  mutation UpdateProductCategories($productId: ID!, $categoryIds: [ID!]!) {
    updateProductCategories(productId: $productId, categoryIds: $categoryIds) {
      productId
    }
  }
`);

const UpdateProductAttributesMutation = graphql(`
  mutation UpdateProductAttributes(
    $productId: ID!
    $attributes: [UpdateProductAttributesInputAttributes!]!
  ) {
    updateProductAttributes(productId: $productId, attributes: $attributes) {
      productId
    }
  }
`);

const CategoriesForProductQuery = graphql(`
  query CategoriesForProduct {
    productCategories {
      edges {
        node {
          id
          name
        }
      }
    }
  }
`);

const AttributesForProductQuery = graphql(`
  query AttributesForProduct {
    productAttributes {
      edges {
        node {
          id
          name
          productAttributeValues {
            edges {
              node {
                id
                label
              }
            }
          }
        }
      }
    }
  }
`);

export const ProductActionsFragment = graphql(`
  fragment ProductActions on Product {
    id
    status
    productCategoryAssignments {
      edges {
        node {
          id
          categoryId
        }
      }
    }
    productAttributeAssignments {
      edges {
        node {
          id
          attributeId
          valueId
        }
      }
    }
  }
`);

interface ProductActionsProps {
  product: FragmentOf<typeof ProductActionsFragment>;
}

interface AttrEntry {
  attributeId: string;
  valueId: string;
}

type DialogType = "manage-categories" | "manage-attributes" | null;

export const ProductActions = ({ product: productFragment }: ProductActionsProps) => {
  const product = readFragment(ProductActionsFragment, productFragment);
  const navigate = useNavigate();
  const toast = useToast();
  const [{ fetching: activating }, activateProduct] = useMutation(ActivateProductMutation);
  const [{ fetching: deactivating }, deactivateProduct] = useMutation(DeactivateProductMutation);
  const [{ fetching: reactivating }, reactivateProduct] = useMutation(ReactivateProductMutation);
  const [{ fetching: deleting }, deleteProduct] = useMutation(DeleteProductMutation);
  const [{ fetching: generatingVariants }, generateVariants] =
    useMutation(GenerateVariantsMutation);
  const [{ fetching: updatingCategories }, updateProductCategories] = useMutation(
    UpdateProductCategoriesMutation,
  );
  const [{ fetching: updatingAttributes }, updateProductAttributes] = useMutation(
    UpdateProductAttributesMutation,
  );

  const [{ data: categoriesData }] = useQuery({ query: CategoriesForProductQuery });
  const [{ data: attributesData }] = useQuery({ query: AttributesForProductQuery });

  const [openDialog, setOpenDialog] = useState<DialogType>(null);

  // --- Categories ---
  const categories = categoriesData?.productCategories.edges.map((e) => e.node) ?? [];
  const currentCategoryIds = new Set(
    product.productCategoryAssignments?.edges
      ?.filter((e) => e.node.categoryId != null)
      .map((e) => e.node.categoryId) ?? [],
  );
  const [selectedCategoryIds, setSelectedCategoryIds] = useState<Set<string>>(
    () => new Set(currentCategoryIds),
  );

  const toggleCategory = (id: string) => {
    setSelectedCategoryIds((prev) => {
      const next = new Set(prev);
      if (next.has(id)) next.delete(id);
      else next.add(id);
      return next;
    });
  };

  const handleSaveCategories = () => {
    void updateProductCategories(
      { productId: product.id, categoryIds: [...selectedCategoryIds] },
      { additionalTypenames: ["ProductCategoryAssignment"] },
    ).then((result) => {
      if (result.error) {
        toast.error(result.error);
        return;
      }
      toast.success("Categories updated");
      setOpenDialog(null);
    });
  };

  // --- Attributes ---
  const isDraft = product.status === "DRAFT";
  const attributes = attributesData?.productAttributes.edges.map((e) => e.node) ?? [];
  const currentAttrs: AttrEntry[] =
    product.productAttributeAssignments?.edges?.map((e) => ({
      attributeId: e.node.attributeId,
      valueId: e.node.valueId,
    })) ?? [];
  const currentAttrIds = new Set(currentAttrs.map((a) => a.attributeId));
  const [selectedAttrs, setSelectedAttrs] = useState<AttrEntry[]>([]);
  const addAllValuesForAttribute = (attrId: string) => {
    const attr = attributes.find((a) => a.id === attrId);
    if (!attr) return;
    const allValues = attr.productAttributeValues?.edges?.map((e) => e.node) ?? [];
    const existing = new Set(
      selectedAttrs.filter((a) => a.attributeId === attrId).map((a) => a.valueId),
    );
    const toAdd = allValues
      .filter((v) => !existing.has(v.id))
      .map((v) => ({ attributeId: attrId, valueId: v.id }));
    setSelectedAttrs((prev) => [...prev, ...toAdd]);
  };

  const removeAttr = (attributeId: string, valueId: string) => {
    setSelectedAttrs((prev) => {
      const idx = prev.findIndex((a) => a.attributeId === attributeId && a.valueId === valueId);
      if (idx === -1) return prev;
      return [...prev.slice(0, idx), ...prev.slice(idx + 1)];
    });
  };

  // Group selected attrs by attribute name for display
  const groupedAttrs = selectedAttrs.reduce<
    Record<string, { attributeId: string; valueId: string; label: string }[]>
  >((acc, a) => {
    const attr = attributes.find((at) => at.id === a.attributeId);
    const attrName = attr?.name ?? a.attributeId;
    const val = attr?.productAttributeValues?.edges?.find((e) => e.node.id === a.valueId)?.node;
    if (!acc[attrName]) acc[attrName] = [];
    acc[attrName].push({
      attributeId: a.attributeId,
      valueId: a.valueId,
      label: val?.label ?? a.valueId,
    });
    return acc;
  }, {});

  const handleSaveAttributes = () => {
    void updateProductAttributes(
      { productId: product.id, attributes: selectedAttrs },
      { additionalTypenames: ["ProductAttributeAssignment"] },
    ).then((result) => {
      if (result.error) {
        toast.error(result.error);
        return;
      }
      toast.success("Attributes updated");
      setOpenDialog(null);
    });
  };

  return (
    <>
      <ActionPanel
        title="Actions"
        actions={[
          {
            key: "edit",
            label: "Edit Product",
            icon: <Pencil />,
            onClick: () => navigate("edit"),
          },
          ...(product.status === "DRAFT"
            ? [
                {
                  key: "activate",
                  label: "Activate Product",
                  icon: <Play />,
                  loading: activating,
                  onClick: () =>
                    void activateProduct(
                      { id: product.id },
                      { additionalTypenames: ["Product"] },
                    ).then((result) => {
                      if (result.error) {
                        toast.error(result.error);
                        return;
                      }
                      toast.success("Product activated successfully");
                    }),
                },
              ]
            : []),
          ...(product.status === "ACTIVE"
            ? [
                {
                  key: "deactivate",
                  label: "Deactivate Product",
                  icon: <Pause />,
                  variant: "destructive" as const,
                  loading: deactivating,
                  onClick: () =>
                    void deactivateProduct(
                      { id: product.id },
                      { additionalTypenames: ["Product"] },
                    ).then((result) => {
                      if (result.error) {
                        toast.error(result.error);
                        return;
                      }
                      toast.success("Product deactivated successfully");
                    }),
                },
              ]
            : []),
          ...(product.status === "ARCHIVED"
            ? [
                {
                  key: "reactivate",
                  label: "Reactivate Product",
                  icon: <RotateCcw />,
                  loading: reactivating,
                  onClick: () =>
                    void reactivateProduct(
                      { id: product.id },
                      { additionalTypenames: ["Product"] },
                    ).then((result) => {
                      if (result.error) {
                        toast.error(result.error);
                        return;
                      }
                      toast.success("Product reactivated successfully");
                    }),
                },
              ]
            : []),
          ...(product.status === "DRAFT"
            ? [
                {
                  key: "delete",
                  label: "Delete Product",
                  icon: <Trash2 />,
                  variant: "destructive" as const,
                  loading: deleting,
                  onClick: () =>
                    void deleteProduct(
                      { id: product.id },
                      { additionalTypenames: ["Product"] },
                    ).then((result) => {
                      if (result.error) {
                        toast.error(result.error);
                        return;
                      }
                      toast.success("Product deleted successfully");
                      void navigate("/product/product");
                    }),
                },
              ]
            : []),
          ...(product.status === "ACTIVE"
            ? [
                {
                  key: "generate-variants",
                  label: "Generate Variants",
                  icon: <Sparkles />,
                  loading: generatingVariants,
                  onClick: () =>
                    void generateVariants(
                      { productId: product.id },
                      { additionalTypenames: ["ProductVariant"] },
                    ).then((result) => {
                      if (result.error) {
                        toast.error(result.error);
                        return;
                      }
                      toast.success("Variants generated successfully");
                    }),
                },
              ]
            : []),
          {
            key: "manage-categories",
            label: "Manage Categories",
            icon: <FolderPlus />,
            onClick: () => {
              setSelectedCategoryIds(new Set(currentCategoryIds));
              setOpenDialog("manage-categories");
            },
          },
          ...(product.status !== "ARCHIVED"
            ? [
                {
                  key: "manage-attributes",
                  label: "Manage Attributes",
                  icon: <Tags />,
                  onClick: () => {
                    setSelectedAttrs([...currentAttrs]);
                    setOpenDialog("manage-attributes");
                  },
                },
              ]
            : []),
        ]}
      />

      <Dialog.Root
        open={openDialog === "manage-categories"}
        onOpenChange={(open) => !open && setOpenDialog(null)}
      >
        <Dialog.Content>
          <Dialog.Header>
            <Dialog.Title>Manage Categories</Dialog.Title>
            <Dialog.Description>Select the categories for this product.</Dialog.Description>
          </Dialog.Header>
          <div className="max-h-60 space-y-1 overflow-y-auto py-4">
            {categories.map((cat) => (
              <label
                key={cat.id}
                className="flex cursor-pointer items-center gap-2 rounded px-2 py-1.5 hover:bg-accent"
              >
                <input
                  type="checkbox"
                  checked={selectedCategoryIds.has(cat.id)}
                  onChange={() => toggleCategory(cat.id)}
                  className="h-4 w-4 rounded border-gray-300"
                />
                <span className="text-sm">{cat.name}</span>
              </label>
            ))}
            {categories.length === 0 && (
              <p className="text-muted-foreground text-sm">No categories available</p>
            )}
          </div>
          <Dialog.Footer>
            <Button variant="outline" onClick={() => setOpenDialog(null)}>
              Cancel
            </Button>
            <Button onClick={handleSaveCategories} disabled={updatingCategories}>
              {updatingCategories ? "Saving..." : "Save"}
            </Button>
          </Dialog.Footer>
        </Dialog.Content>
      </Dialog.Root>

      <Dialog.Root
        open={openDialog === "manage-attributes"}
        onOpenChange={(open) => !open && setOpenDialog(null)}
      >
        <Dialog.Content>
          <Dialog.Header>
            <Dialog.Title>Manage Attributes</Dialog.Title>
            <Dialog.Description>
              {isDraft
                ? "Add or remove attributes and values."
                : "Add values to existing attributes. Removal is locked for active products."}
            </Dialog.Description>
          </Dialog.Header>
          <div className="max-h-80 space-y-3 overflow-y-auto py-4">
            {Object.entries(groupedAttrs).map(([attrName, entries]) => (
              <div key={attrName}>
                <p className="mb-1 text-xs font-medium text-muted-foreground">{attrName}</p>
                <div className="space-y-1">
                  {entries.map((entry) => (
                    <div
                      key={`${entry.attributeId}:${entry.valueId}`}
                      className="flex items-center justify-between rounded border px-3 py-1.5 text-sm"
                    >
                      <span>{entry.label}</span>
                      <button
                        type="button"
                        onClick={() => removeAttr(entry.attributeId, entry.valueId)}
                        className="text-muted-foreground hover:text-destructive"
                      >
                        <X className="h-4 w-4" />
                      </button>
                    </div>
                  ))}
                </div>
              </div>
            ))}
            {selectedAttrs.length === 0 && (
              <p className="text-muted-foreground text-sm">No attributes assigned</p>
            )}
            <div>
              <select
                className="flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm"
                value=""
                onChange={(e) => {
                  if (e.target.value) addAllValuesForAttribute(e.target.value);
                }}
              >
                <option value="">
                  {isDraft ? "Add attribute..." : "Add values to existing attribute..."}
                </option>
                {(isDraft ? attributes : attributes.filter((a) => currentAttrIds.has(a.id))).map(
                  (a) => (
                    <option key={a.id} value={a.id}>
                      {a.name}
                    </option>
                  ),
                )}
              </select>
            </div>
          </div>
          <Dialog.Footer>
            <Button variant="outline" onClick={() => setOpenDialog(null)}>
              Cancel
            </Button>
            <Button onClick={handleSaveAttributes} disabled={updatingAttributes}>
              {updatingAttributes ? "Saving..." : "Save"}
            </Button>
          </Dialog.Footer>
        </Dialog.Content>
      </Dialog.Root>
    </>
  );
};
