import { zodResolver } from "@hookform/resolvers/zod";
import { Button, Field, Form, Select, useNavigate } from "@tailor-platform/app-shell";
import { X } from "lucide-react";
import { useState } from "react";
import { Controller, useForm } from "react-hook-form";
import { useMutation, useQuery } from "urql";
import { z } from "zod";
import { graphql } from "@/graphql";
import { useToast } from "@/hooks/use-toast";

const UnitsQuery = graphql(`
  query UnitsForProductForm {
    units {
      edges {
        node {
          id
          name
          symbol
        }
      }
    }
  }
`);

const CategoriesQuery = graphql(`
  query CategoriesForProductForm {
    productCategories {
      edges {
        node {
          id
          name
        }
      }
    }
  }
`);

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

const CreateProductMutation = graphql(`
  mutation CreateProduct(
    $code: String!
    $name: String!
    $description: String
    $unitId: ID!
    $categoryIds: [ID!]
    $attributes: [CreateProductInputAttributes!]
  ) {
    createProduct(
      code: $code
      name: $name
      description: $description
      unitId: $unitId
      categoryIds: $categoryIds
      attributes: $attributes
    ) {
      id
      code
      name
      status
    }
  }
`);

const formSchema = z.object({
  code: z.string().min(1, "Code is required"),
  name: z.string().min(1, "Name is required"),
  description: z.string().optional(),
  unitId: z.string().min(1, "Unit is required"),
  categoryIds: z.array(z.string()).optional(),
});

type FormValues = z.infer<typeof formSchema>;

export const CreateProductForm = () => {
  const navigate = useNavigate();
  const toast = useToast();
  const [, createProduct] = useMutation(CreateProductMutation);
  const [{ data: unitsData }] = useQuery({ query: UnitsQuery });
  const [{ data: categoriesData }] = useQuery({ query: CategoriesQuery });
  const [{ data: attributesData }] = useQuery({ query: AttributesQuery });

  const units =
    unitsData?.units?.edges?.map((edge) => {
      const node = edge.node;
      return { id: node.id, label: `${node.name} (${node.symbol})` };
    }) ?? [];

  const categories = categoriesData?.productCategories?.edges?.map((e) => e.node) ?? [];
  const attributes = attributesData?.productAttributes?.edges?.map((e) => e.node) ?? [];

  const [selectedAttrs, setSelectedAttrs] = useState<{ attributeId: string; valueId: string }[]>(
    [],
  );

  const addAllValuesForAttribute = (attrId: string) => {
    const attr = attributes.find((a) => a.id === attrId);
    if (!attr) return;
    const values = attr.productAttributeValues?.edges?.map((e) => e.node) ?? [];
    const existing = new Set(
      selectedAttrs.filter((a) => a.attributeId === attrId).map((a) => a.valueId),
    );
    const toAdd = values
      .filter((v) => !existing.has(v.id))
      .map((v) => ({ attributeId: attrId, valueId: v.id }));
    setSelectedAttrs((prev) => [...prev, ...toAdd]);
  };

  const removeAttribute = (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)];
    });
  };

  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 form = useForm<FormValues>({
    resolver: zodResolver(formSchema),
    defaultValues: {
      code: "",
      name: "",
      description: "",
      unitId: "",
      categoryIds: [],
    },
  });

  const onSubmit = (values: FormValues) => {
    const categoryIds = values.categoryIds?.length ? values.categoryIds : undefined;
    const attrInput = selectedAttrs.length > 0 ? selectedAttrs : undefined;
    void createProduct(
      {
        ...values,
        description: values.description || undefined,
        categoryIds,
        attributes: attrInput,
      },
      { additionalTypenames: ["Product"] },
    ).then((result) => {
      if (result.error) {
        toast.error(result.error);
        return;
      }
      toast.success("Product created successfully");
      void navigate("..");
    });
  };

  const onCancel = () => {
    void navigate("..");
  };

  return (
    <Form
      noValidate
      onSubmit={(e) => void form.handleSubmit(onSubmit)(e)}
      className="max-w-md space-y-4"
    >
      <Controller
        control={form.control}
        name="code"
        render={({ field, fieldState }) => (
          <Field.Root name={field.name} invalid={fieldState.invalid}>
            <Field.Label>Code</Field.Label>
            <Field.Control placeholder="Enter product code" {...field} />
            {fieldState.error && <Field.Error match>{fieldState.error.message}</Field.Error>}
          </Field.Root>
        )}
      />
      <Controller
        control={form.control}
        name="name"
        render={({ field, fieldState }) => (
          <Field.Root name={field.name} invalid={fieldState.invalid}>
            <Field.Label>Name</Field.Label>
            <Field.Control placeholder="Enter product name" {...field} />
            {fieldState.error && <Field.Error match>{fieldState.error.message}</Field.Error>}
          </Field.Root>
        )}
      />
      <Controller
        control={form.control}
        name="description"
        render={({ field, fieldState }) => (
          <Field.Root name={field.name} invalid={fieldState.invalid}>
            <Field.Label>Description</Field.Label>
            <Field.Control placeholder="Enter product description (optional)" {...field} />
            {fieldState.error && <Field.Error match>{fieldState.error.message}</Field.Error>}
          </Field.Root>
        )}
      />
      <Controller
        control={form.control}
        name="unitId"
        render={({ field, fieldState }) => (
          <Field.Root name={field.name} invalid={fieldState.invalid}>
            <Field.Label>Unit</Field.Label>
            <Select
              items={units}
              value={units.find((u) => u.id === field.value) ?? null}
              onValueChange={(item) => field.onChange(item?.id ?? "")}
              mapItem={(u) => ({ label: u.label, key: u.id })}
              placeholder="Select a unit"
            />
            {fieldState.error && <Field.Error match>{fieldState.error.message}</Field.Error>}
          </Field.Root>
        )}
      />
      <Controller
        control={form.control}
        name="categoryIds"
        render={({ field, fieldState }) => (
          <Field.Root name={field.name} invalid={fieldState.invalid}>
            <Field.Label>Categories</Field.Label>
            <Select
              multiple
              items={categories}
              value={categories.filter((c) => field.value?.includes(c.id))}
              onValueChange={(selected) => field.onChange(selected.map((c) => c.id))}
              mapItem={(cat) => ({ label: cat.name, key: cat.id })}
              placeholder="Select categories"
            />
            {fieldState.error && <Field.Error match>{fieldState.error.message}</Field.Error>}
          </Field.Root>
        )}
      />
      <div>
        <label className="mb-1 block text-sm font-medium">Attributes</label>
        <div className="space-y-2">
          {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={() => removeAttribute(entry.attributeId, entry.valueId)}
                      className="text-muted-foreground hover:text-destructive"
                    >
                      <X className="h-4 w-4" />
                    </button>
                  </div>
                ))}
              </div>
            </div>
          ))}
        </div>
        <div className="mt-2">
          <Select
            items={attributes}
            value={null}
            onValueChange={(item) => {
              if (item) addAllValuesForAttribute(item.id);
            }}
            mapItem={(a) => ({ label: a.name, key: a.id })}
            placeholder="Add attribute..."
          />
        </div>
      </div>
      <div className="flex gap-2">
        <Button type="submit">Create</Button>
        <Button type="button" variant="outline" onClick={onCancel}>
          Cancel
        </Button>
      </div>
    </Form>
  );
};
