import { DEFAULT_FIELD_FONT_SIZE, type TDropdownFieldMeta as DropdownFieldMeta } from '@documenso/lib/types/field-meta';
import { Form, FormControl, FormField, FormItem, FormLabel, FormMessage } from '@documenso/ui/primitives/form/form';
import { Input } from '@documenso/ui/primitives/input';
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from '@documenso/ui/primitives/select';
import { Separator } from '@documenso/ui/primitives/separator';
import { zodResolver } from '@hookform/resolvers/zod';
import { msg } from '@lingui/core/macro';
import { Trans, useLingui } from '@lingui/react/macro';
import { PlusIcon, Trash } from 'lucide-react';
import { useEffect } from 'react';
import { useForm, useWatch } from 'react-hook-form';
import { z } from 'zod';

import {
  EditorGenericFontSizeField,
  EditorGenericReadOnlyField,
  EditorGenericRequiredField,
} from './editor-field-generic-field-forms';

const ZDropdownFieldFormSchema = z.object({
  defaultValue: z.string().optional(),
  values: z
    .object({
      value: z.string().min(1, {
        message: msg`Option value cannot be empty`.id,
      }),
    })
    .array()
    .min(1, {
      message: msg`Dropdown must have at least one option`.id,
    })
    .superRefine((values, ctx) => {
      const seen = new Map<string, number[]>(); // value → indices

      values.forEach((item, index) => {
        const key = item.value;
        if (!seen.has(key)) {
          seen.set(key, []);
        }
        seen.get(key)!.push(index);
      });

      for (const [key, indices] of seen) {
        if (indices.length > 1 && key.trim() !== '') {
          for (const i of indices) {
            ctx.addIssue({
              code: z.ZodIssueCode.custom,
              message: msg`Duplicate values are not allowed`.id,
              path: [i, 'value'],
            });
          }
        }
      }
    }),
  required: z.boolean().optional(),
  readOnly: z.boolean().optional(),
  fontSize: z.number().optional(),
});

type TDropdownFieldFormSchema = z.infer<typeof ZDropdownFieldFormSchema>;

type EditorFieldDropdownFormProps = {
  value: DropdownFieldMeta | undefined;
  onValueChange: (value: DropdownFieldMeta) => void;
};

export const EditorFieldDropdownForm = ({
  value = {
    type: 'dropdown',
  },
  onValueChange,
}: EditorFieldDropdownFormProps) => {
  const { t } = useLingui();

  const form = useForm<TDropdownFieldFormSchema>({
    resolver: zodResolver(ZDropdownFieldFormSchema),
    mode: 'onChange',
    defaultValues: {
      defaultValue: value.defaultValue,
      values: value.values || [{ value: t`Option 1` }],
      required: value.required || false,
      readOnly: value.readOnly || false,
      fontSize: value.fontSize || DEFAULT_FIELD_FONT_SIZE,
    },
  });

  const formValues = useWatch({
    control: form.control,
  });

  const addValue = () => {
    const currentValues = form.getValues('values') || [];

    let newValue = t`New option`;

    // Iterate to create a unique value
    for (let i = 0; i < currentValues.length; i++) {
      newValue = t`New option ${i + 1}`;
      if (currentValues.some((item) => item.value === t`New option ${i + 1}`)) {
        newValue = t`New option ${i + 1}`;
      } else {
        break;
      }
    }

    const newValues = [...currentValues, { value: newValue }];

    form.setValue('values', newValues);
  };

  const removeValue = (index: number) => {
    const currentValues = form.getValues('values') || [];

    if (currentValues.length === 1) {
      return;
    }

    const newValues = [...currentValues];
    const removedValue = currentValues[index].value;
    newValues.splice(index, 1);

    form.setValue('values', newValues);

    if (form.getValues('defaultValue') === removedValue) {
      form.setValue('defaultValue', undefined);
    }
  };

  useEffect(() => {
    const validatedFormValues = ZDropdownFieldFormSchema.safeParse(formValues);

    if (validatedFormValues.success) {
      onValueChange({
        type: 'dropdown',
        ...validatedFormValues.data,
      });
    }
  }, [formValues]);

  return (
    <Form {...form}>
      <form>
        <fieldset className="flex flex-col gap-2">
          <EditorGenericFontSizeField formControl={form.control} />

          {/* Todo: Envelopes This is buggy. */}
          <FormField
            control={form.control}
            name="defaultValue"
            render={({ field }) => (
              <FormItem>
                <FormLabel>
                  <Trans>Select default option</Trans>
                </FormLabel>
                <FormControl>
                  <Select
                    {...field}
                    value={field.value ?? '-1'}
                    onValueChange={(value) => field.onChange(value === '-1' ? undefined : value)}
                  >
                    <SelectTrigger
                      data-testid="field-form-defaultValue"
                      className="w-full bg-background text-muted-foreground"
                    >
                      <SelectValue placeholder={t`Default Value`} />
                    </SelectTrigger>
                    <SelectContent position="popper">
                      {(formValues.values || [])
                        .filter((item) => item.value)
                        .map((item, index) => (
                          <SelectItem key={index} value={item.value || ''}>
                            {item.value}
                          </SelectItem>
                        ))}

                      <SelectItem value={'-1'}>
                        <Trans>Default Value</Trans>
                      </SelectItem>
                    </SelectContent>
                  </Select>
                </FormControl>
                <FormMessage />
              </FormItem>
            )}
          />

          <div className="mt-1">
            <EditorGenericRequiredField formControl={form.control} />
          </div>

          <EditorGenericReadOnlyField formControl={form.control} />

          <section className="space-y-2">
            <div className="-mx-4 mt-2 mb-4">
              <Separator />
            </div>

            <div className="flex flex-row items-center justify-between gap-2">
              <p className="font-medium text-sm">
                <Trans>Dropdown values</Trans>
              </p>

              <button type="button" data-testid="field-form-values-add" onClick={addValue}>
                <PlusIcon className="h-4 w-4" />
              </button>
            </div>

            <ul className="space-y-2">
              {(formValues.values || []).map((value, index) => (
                <li key={`dropdown-value-${index}`} className="flex flex-row gap-2">
                  <FormField
                    control={form.control}
                    name={`values.${index}.value`}
                    render={({ field }) => (
                      <FormItem className="w-full">
                        <FormControl>
                          <Input data-testid={`field-form-values-${index}-value`} {...field} />
                        </FormControl>
                        <FormMessage />
                      </FormItem>
                    )}
                  />

                  <button
                    type="button"
                    data-testid={`field-form-values-${index}-remove`}
                    className="flex h-10 w-10 items-center justify-center text-slate-500 hover:opacity-80 disabled:cursor-not-allowed disabled:opacity-50"
                    onClick={() => removeValue(index)}
                  >
                    <Trash className="h-5 w-5" />
                  </button>
                </li>
              ))}
            </ul>
          </section>
        </fieldset>
      </form>
    </Form>
  );
};
