"use client";
import React, { useState, useRef, useCallback, useEffect } from 'react';
import { useTranslations } from "next-intl";
import { useForm, useFieldArray, Control } from 'react-hook-form';
import { ImageIcon, Loader2 } from 'lucide-react';
import { PlusIcon } from "@radix-ui/react-icons";
import z from 'zod';
import { zodResolver } from '@hookform/resolvers/zod';
import { toast } from 'sonner';
import {
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogFooter,
  DialogDescription
} from '@/components/ui/dialog';
import { Button } from '@/components/ui/button';
import { SelectControl } from "@/components/form/control/select.control";
import { InputControl } from "@/components/form/control/input.control";
import { useMediaPicker } from "@/components/ui/media-picker";
import { MediaPreview } from "@/components/dashboard/media/media-preview";
import type { PostMediaData } from '@/lib/database';
import { api } from "@/lib/trpc/client";
import { WidgetPosition } from '@/config/enums/tip-tap';

const schema = z.object({
  variant: z.nativeEnum(WidgetPosition),
  media: z.array(z.custom<PostMediaData>()).min(1)
});

type InlineImageForm = z.infer<typeof schema>;

const options = [
  {
    label: 'Default',
    value: WidgetPosition.CENTER
  },
  {
    label: 'Full Width',
    value: WidgetPosition.FULL
  },
  {
    label: '2/3 Width',
    value: WidgetPosition.ALIGN_LEFT
  }
];
const defaultValues: InlineImageForm = {
  variant: WidgetPosition.CENTER,
  media: []
};

type Props = {
  open: boolean;
  onOpenChange: (v: boolean) => void;
  initialValues?: InlineImageForm;
  onSubmit: (data: InlineImageForm) => void;
  title: string;
  description: string;
};

export function InlineImageDialog({
  open,
  onOpenChange,
  initialValues,
  onSubmit,
  title,
  description
}: Props) {
  const [picking, setPicking] = useState(false);
  const { control, reset, handleSubmit, getValues } = useForm<InlineImageForm>({
    resolver: zodResolver(schema),
    defaultValues: initialValues ?? defaultValues
  });

  const t = useTranslations();

  const { fields, replace, remove } = useFieldArray({
    control,
    name: 'media',
    keyName: 'fieldId'
  });

  const utils = api.useUtils();

  const mediaPicker = useMediaPicker();

  const handleSelect = useCallback((selectedItems: PostMediaData[]) => {
    const currentMedia = getValues('media') ?? [];
    const currentIds = new Set(currentMedia.map((m) => m.id));

    const existing = currentMedia.filter((m) =>
        selectedItems.some((s) => s.id === m.id)
    );

    const newlyAdded = selectedItems
        .filter((s) => !currentIds.has(s.id))
        .map((s) => ({
          ...s,
          alt: s.alt ?? '',
          caption: s.caption ?? '',
          author: s.author ?? ''
        }));

    const medias = [...existing, ...newlyAdded];

    if(medias.length > 0) {
      mediaPicker.attach(medias.map(m => m.id));
    }

    replace(medias);
  }, [getValues, replace, mediaPicker]);

  const handleSelectMedia = useCallback(async () => {
    try {
      setPicking(true);

      const ids = await mediaPicker.pick({
        withAttachments: true,
        multiple: true,
        defaultAttached: true,
        selected: fields.map((f) => f.id)
      });

      const medias = await utils.media.list.fetch({
        ids
      });

      handleSelect(medias);
    }
    catch {}
    finally {
      setPicking(false);
    }
  }, [mediaPicker, fields, utils.media.list, handleSelect]);

  const handleSelectMediaRef = useRef(handleSelectMedia);
  handleSelectMediaRef.current = handleSelectMedia;

  useEffect(() => {
    if (open) {
      const values = initialValues ?? defaultValues;

      reset(values);

      if(values.media.length === 0) {
        handleSelectMediaRef.current();
      }
    }
  }, [open, initialValues, reset]);

  return (
    <Dialog open={open} onOpenChange={onOpenChange}>
      <DialogContent>
        <DialogHeader>
          <DialogTitle>{title}</DialogTitle>
          <DialogDescription>{description}</DialogDescription>
        </DialogHeader>

        <div className='flex max-h-[70vh] flex-col gap-4 overflow-y-auto'>
          <div className="flex flex-row justify-between">
            <SelectControl
              control={control as unknown as Control}
              label={t("dashboard.tiptap.inlineImage.fields.variant.label")}
              name="variant"
            >
              <SelectControl.Trigger>
                <SelectControl.Value placeholder={t("dashboard.tiptap.inlineImage.fields.variant.placeholder")} />
              </SelectControl.Trigger>

              <SelectControl.Content>
                <SelectControl.Group>
                  {options.map((option) => (
                    <SelectControl.Item key={option.value} value={option.value}>
                      {option.label}
                    </SelectControl.Item>
                  ))}
                </SelectControl.Group>
              </SelectControl.Content>
            </SelectControl>

            <Button
              type="button"
              variant="ghost"
              title={t("dashboard.tiptap.inlineImage.actions.addImage")}
              size="icon"
              disabled={picking}
              onClick={handleSelectMedia}
            >
              {picking ? (
                <Loader2 className='animate-spin md:size-5' />
              ) : (
                <PlusIcon />
              )}
            </Button>
          </div>

          {fields.map((media, index) => {
            return (
              <div
                key={media.fieldId}
                className='flex gap-2'
              >
                <MediaPreview
                  className="basis-[125px]"
                  size={100}
                  mimeType={media.mimeType}
                  alt={media.alt || "Select Image"}
                  url={media.url}
                  onDelete={() => remove(index)} />

                <div className='flex w-full flex-col gap-2'>
                  <InputControl
                    control={control as unknown as Control}
                    label={t("dashboard.media.editor.fields.alt.label")}
                    placeholder={t("dashboard.media.editor.fields.alt.placeholder")}
                    name={`media.${index}.alt`} />

                  <InputControl
                    control={control as unknown as Control}
                    label={t("dashboard.media.editor.fields.caption.label")}
                    placeholder={t("dashboard.media.editor.fields.caption.placeholder")}
                    name={`media.${index}.caption`} />

                  <InputControl
                    control={control as unknown as Control}
                    label={t("dashboard.media.editor.fields.author.label")}
                    placeholder={t("dashboard.media.editor.fields.author.placeholder")}
                    name={`media.${index}.author`} />
                </div>
              </div>
            );
          })}

          {fields.length === 0 && (
            <div className="flex items-center justify-center h-5">
              <Button
                disabled={picking}
                onClick={handleSelectMedia}
              >
                {picking ? (
                    <Loader2 className='animate-spin md:size-5' />
                ) : (
                    <ImageIcon />
                )}
                {t("dashboard.tiptap.inlineImage.actions.addImage")}
              </Button>
            </div>
          )}

          <DialogFooter>
            <Button
              type='button'
              variant='outline'
              onClick={() => {
                onOpenChange(false);
                reset(defaultValues);
              }}
            >
              {t("dashboard.general.actions.cancel")}
            </Button>

            <Button
              type='button'
              onClick={handleSubmit(onSubmit, () => {
                toast.error(t("dashboard.tiptap.inlineImage.fields.media.error"));
              })}
            >
              {t("dashboard.general.actions.save")}
            </Button>
          </DialogFooter>
        </div>
      </DialogContent>
    </Dialog>
  );
}
