'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { Loader2, Plus, Smile, X } from 'lucide-react';
import { Button } from '@/components/ui/button';
import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog';
import { Input } from '@/components/ui/input';
import { createFilePreviewUrl, isCompressibleImageFile, readImageDimensions } from '@/lib/chat-image-compress';
import { formatFileSize } from '@/lib/chat-media';
import { cn } from '@/lib/utils';

export interface ChatMediaComposeItem {
  id: string;
  file: File;
  previewUrl: string | null;
  sendAsFile: boolean;
  width?: number;
  height?: number;
}

const MAX_FILES = 10;

function createComposeItem(file: File, sendAsFile = false): ChatMediaComposeItem {
  return {
    id: crypto.randomUUID(),
    file,
    previewUrl: createFilePreviewUrl(file),
    sendAsFile
  };
}

export function useChatMediaComposer() {
  const [open, setOpen] = useState(false);
  const [items, setItems] = useState<ChatMediaComposeItem[]>([]);
  const [caption, setCaption] = useState('');
  const [sendAsFile, setSendAsFile] = useState(false);

  const reset = useCallback(() => {
    setItems((current) => {
      current.forEach((item) => {
        if (item.previewUrl) URL.revokeObjectURL(item.previewUrl);
      });
      return [];
    });
    setCaption('');
    setSendAsFile(false);
  }, []);

  const close = useCallback(() => {
    setOpen(false);
    reset();
  }, [reset]);

  const openWithFiles = useCallback(async (files: File[], options?: { sendAsFile?: boolean }) => {
    const limited = files.slice(0, MAX_FILES);
    const initialSendAsFile = options?.sendAsFile ?? false;
    const nextItems = await Promise.all(
      limited.map(async (file) => {
        const item = createComposeItem(file, initialSendAsFile);
        if (isCompressibleImageFile(file)) {
          const dimensions = await readImageDimensions(file);
          item.width = dimensions.width;
          item.height = dimensions.height;
        }
        return item;
      })
    );
    setItems(nextItems);
    setSendAsFile(initialSendAsFile);
    setCaption('');
    setOpen(true);
  }, []);

  const addFiles = useCallback(async (files: File[]) => {
    const limited = files.slice(0, MAX_FILES);
    if (!limited.length) return;

    const appended = await Promise.all(
      limited.map(async (file) => {
        const item = createComposeItem(file, sendAsFile);
        if (isCompressibleImageFile(file)) {
          const dimensions = await readImageDimensions(file);
          item.width = dimensions.width;
          item.height = dimensions.height;
        }
        return item;
      })
    );

    setItems((current) => [...current, ...appended].slice(0, MAX_FILES));
  }, [sendAsFile]);

  const removeItem = useCallback((id: string) => {
    setItems((current) => {
      const target = current.find((item) => item.id === id);
      if (target?.previewUrl) URL.revokeObjectURL(target.previewUrl);
      const next = current.filter((item) => item.id !== id);
      if (!next.length) {
        setOpen(false);
        setCaption('');
        setSendAsFile(false);
      }
      return next;
    });
  }, []);

  useEffect(() => {
    setItems((current) => current.map((item) => ({ ...item, sendAsFile })));
  }, [sendAsFile]);

  const hasImages = useMemo(() => items.some((item) => isCompressibleImageFile(item.file)), [items]);

  return {
    open,
    items,
    caption,
    sendAsFile,
    hasImages,
    maxFiles: MAX_FILES,
    setCaption,
    setSendAsFile,
    openWithFiles,
    addFiles,
    removeItem,
    close
  };
}

interface ChatMediaComposeDialogProps {
  open: boolean;
  items: ChatMediaComposeItem[];
  caption: string;
  sendAsFile: boolean;
  hasImages: boolean;
  maxFiles: number;
  sending?: boolean;
  onCaptionChange: (value: string) => void;
  onSendAsFileChange: (value: boolean) => void;
  onRemoveItem: (id: string) => void;
  onAddFiles: (files: File[]) => void;
  onClose: () => void;
  onSend: () => void;
}

export function ChatMediaComposeDialog({
  open,
  items,
  caption,
  sendAsFile,
  hasImages,
  maxFiles,
  sending = false,
  onCaptionChange,
  onSendAsFileChange,
  onRemoveItem,
  onAddFiles,
  onClose,
  onSend
}: ChatMediaComposeDialogProps) {
  const addInputRef = useRef<HTMLInputElement>(null);
  const activePreview = items[0] ?? null;

  return (
    <Dialog open={open} onOpenChange={(next) => !next && onClose()}>
      <DialogContent className="overflow-hidden rounded-[20px] p-0 sm:max-w-[460px]">
        <div className="border-b border-[#eceef4] px-5 py-4">
          <DialogHeader className="mb-0">
            <DialogTitle>{items.length > 1 ? `Отправить ${items.length} файла` : 'Отправить изображение'}</DialogTitle>
          </DialogHeader>
        </div>

        <div className="space-y-4 px-5 py-4">
          {activePreview ? (
            <div className="relative overflow-hidden rounded-2xl bg-[#0f1117]">
              {activePreview.previewUrl ? (
                // eslint-disable-next-line @next/next/no-img-element
                <img
                  src={activePreview.previewUrl}
                  alt={activePreview.file.name}
                  className="mx-auto max-h-[320px] w-full object-contain"
                />
              ) : (
                <div className="flex min-h-[180px] flex-col items-center justify-center gap-2 px-6 text-center text-white/80">
                  <p className="text-sm font-medium">{activePreview.file.name}</p>
                  <p className="text-xs text-white/55">{formatFileSize(activePreview.file.size)}</p>
                </div>
              )}
              <button
                type="button"
                className="absolute right-3 top-3 rounded-full bg-black/55 p-1.5 text-white transition hover:bg-black/70"
                aria-label="Удалить файл"
                onClick={() => onRemoveItem(activePreview.id)}
              >
                <X className="h-4 w-4" />
              </button>
            </div>
          ) : null}

          {items.length > 1 ? (
            <div className="grid grid-cols-5 gap-2">
              {items.map((item) => (
                <button
                  key={item.id}
                  type="button"
                  className="group relative aspect-square overflow-hidden rounded-xl bg-[#eef1f6]"
                  onClick={() => onRemoveItem(item.id)}
                  title="Нажмите, чтобы удалить"
                >
                  {item.previewUrl ? (
                    // eslint-disable-next-line @next/next/no-img-element
                    <img src={item.previewUrl} alt="" className="h-full w-full object-cover" />
                  ) : (
                    <div className="flex h-full items-center justify-center px-1 text-[10px] text-[#667085]">{item.file.name.slice(0, 8)}</div>
                  )}
                  <span className="absolute inset-0 bg-black/0 transition group-hover:bg-black/20" />
                </button>
              ))}
            </div>
          ) : activePreview?.previewUrl ? (
            <p className="text-center text-xs text-[#667085]">Для редактирования нажмите на изображение</p>
          ) : null}

          {hasImages ? (
            <label className="flex cursor-pointer items-center gap-3 rounded-xl bg-[#f4f5f8] px-3 py-2.5 text-sm">
              <input
                type="checkbox"
                checked={sendAsFile}
                onChange={(event) => onSendAsFileChange(event.target.checked)}
                className="h-4 w-4 rounded border-[#cfd5df]"
              />
              <span>Отправить как файл</span>
            </label>
          ) : null}

          <div className="relative">
            <Input
              value={caption}
              onChange={(event) => onCaptionChange(event.target.value)}
              placeholder="Подпись"
              className="rounded-xl pr-10"
              onKeyDown={(event) => {
                if (event.key === 'Enter' && !event.shiftKey) {
                  event.preventDefault();
                  onSend();
                }
              }}
            />
            <Smile className="pointer-events-none absolute right-3 top-1/2 h-4 w-4 -translate-y-1/2 text-[#98a2b3]" />
          </div>
        </div>

        <div className="flex items-center justify-between border-t border-[#eceef4] px-5 py-3">
          <Button
            type="button"
            variant="ghost"
            className="text-[#3390ec]"
            disabled={items.length >= maxFiles || sending}
            onClick={() => addInputRef.current?.click()}
          >
            <Plus className="mr-1 h-4 w-4" />
            Добавить
          </Button>
          <div className="flex items-center gap-2">
            <Button type="button" variant="ghost" disabled={sending} onClick={onClose}>
              Отмена
            </Button>
            <Button type="button" disabled={!items.length || sending} onClick={onSend}>
              {sending ? <Loader2 className="h-4 w-4 animate-spin" /> : 'Отправить'}
            </Button>
          </div>
        </div>

        <input
          ref={addInputRef}
          type="file"
          className="hidden"
          multiple
          accept="*/*"
          onChange={(event) => {
            const files = Array.from(event.target.files ?? []);
            if (files.length) onAddFiles(files);
            event.target.value = '';
          }}
        />
      </DialogContent>
    </Dialog>
  );
}

interface ChatMediaDropOverlayProps {
  visible: boolean;
  onDropCompressed: (files: File[]) => void;
  onDropAsFile: (files: File[]) => void;
}

export function ChatMediaDropOverlay({ visible, onDropCompressed, onDropAsFile }: ChatMediaDropOverlayProps) {
  if (!visible) return null;

  return (
    <div className="pointer-events-none absolute inset-0 z-30 flex flex-col gap-3 bg-[#0f1117]/78 p-4 backdrop-blur-[1px]">
      <DropZone
        title="Перетащите сюда фотографии"
        subtitle="для отправки их без сжатия"
        className="flex-1 border-white/20 bg-white/5 text-white/90"
        onDrop={onDropAsFile}
      />
      <DropZone
        title="Перетащите сюда фотографии"
        subtitle="для быстрой отправки"
        className="flex-1 border-[#3390ec]/40 bg-[#3390ec]/10 text-[#dbeafe]"
        onDrop={onDropCompressed}
      />
    </div>
  );
}

function DropZone({
  title,
  subtitle,
  className,
  onDrop
}: {
  title: string;
  subtitle: string;
  className?: string;
  onDrop: (files: File[]) => void;
}) {
  return (
    <div
      className={cn(
        'pointer-events-auto flex flex-col items-center justify-center rounded-[24px] border-2 border-dashed px-6 text-center transition',
        className
      )}
      onDragOver={(event) => {
        event.preventDefault();
        event.dataTransfer.dropEffect = 'copy';
      }}
      onDrop={(event) => {
        event.preventDefault();
        event.stopPropagation();
        const files = Array.from(event.dataTransfer.files ?? []);
        if (files.length) onDrop(files);
      }}
    >
      <p className="text-lg font-medium">{title}</p>
      <p className="mt-1 text-sm opacity-80">{subtitle}</p>
    </div>
  );
}

export function extractFilesFromDataTransfer(dataTransfer: DataTransfer | null) {
  if (!dataTransfer) return [] as File[];
  return Array.from(dataTransfer.files ?? []);
}

export function extractFilesFromClipboard(dataTransfer: DataTransfer | null) {
  if (!dataTransfer) return [] as File[];
  const files: File[] = [];
  for (const item of Array.from(dataTransfer.items ?? [])) {
    if (item.kind !== 'file') continue;
    const file = item.getAsFile();
    if (file) files.push(file);
  }
  if (files.length) return files;
  return Array.from(dataTransfer.files ?? []);
}
