import { ReactNode, RefObject, useCallback, useMemo, useRef, useState } from 'react';
import { createContext, useContextSelector } from 'use-context-selector';
import { v4 as uuidv4 } from 'uuid';
import { isSupportedImageFile, uploadImageAttachment } from '../services/attachments';
import { findFirstPlaceholder } from '../utils/workflowTemplate';

export interface ComposerAttachment {
  id: string;
  name: string;
  mime: string;
  kind: 'image';
  status: 'uploading' | 'ready' | 'error';
  /** Object URL used only for the local thumbnail while the composer owns it. */
  previewUrl: string;
  attachmentId?: number;
  url?: string;
  width?: number;
  height?: number;
  dataUrl?: string;
}

const isAcceptedFile = (file: File) => isSupportedImageFile(file);

interface ComposerContextProps {
  draft: string;
  setDraft: React.Dispatch<React.SetStateAction<string>>;
  textareaRef: RefObject<HTMLTextAreaElement>;
  focusComposer: () => void;
  populateDraft: (value: string) => void;
  applyTemplate: (text: string) => void;
  attachments: ComposerAttachment[];
  addFiles: (files: FileList | File[]) => void;
  removeAttachment: (id: string) => void;
  clearAttachments: () => void;
}

const ComposerContext = createContext<ComposerContextProps>({
  draft: '',
  setDraft: () => {},
  textareaRef: { current: null },
  focusComposer: () => {},
  populateDraft: () => {},
  applyTemplate: () => {},
  attachments: [],
  addFiles: () => {},
  removeAttachment: () => {},
  clearAttachments: () => {},
});

export function ComposerProvider({ children }: { children: ReactNode }) {
  const [draft, setDraft] = useState('');
  const [attachments, setAttachments] = useState<ComposerAttachment[]>([]);
  const textareaRef = useRef<HTMLTextAreaElement>(null);

  const focusComposer = useCallback(() => {
    window.setTimeout(() => textareaRef.current?.focus(), 0);
  }, []);

  const populateDraft = useCallback((value: string) => {
    setDraft(value);
    focusComposer();
  }, [focusComposer]);

  // Load a workflow's expanded template, then select the first [placeholder] so the
  // user can type over it (and Tab to the next — handled in the composer).
  const applyTemplate = useCallback((text: string) => {
    setDraft(text);
    window.setTimeout(() => {
      const el = textareaRef.current;
      if (!el) return;
      el.focus();
      const range = findFirstPlaceholder(text);
      if (range) el.setSelectionRange(range[0], range[1]);
      else el.setSelectionRange(text.length, text.length);
      el.style.height = 'auto';
      el.style.height = `${el.scrollHeight}px`;
    }, 0);
  }, []);

  const updateAttachment = useCallback((id: string, patch: Partial<ComposerAttachment>) => {
    setAttachments((prev) => prev.map((item) => (item.id === id ? { ...item, ...patch } : item)));
  }, []);

  const addFiles = useCallback((files: FileList | File[]) => {
    const list = Array.from(files).filter(isAcceptedFile);
    list.forEach((file) => {
      const id = uuidv4();
      const previewUrl = URL.createObjectURL(file);
      setAttachments((prev) => [
        ...prev,
        { id, name: file.name, mime: file.type, kind: 'image', status: 'uploading', previewUrl },
      ]);
      uploadImageAttachment(file)
        .then((uploaded) => updateAttachment(id, {
          status: 'ready',
          attachmentId: uploaded.attachmentId,
          name: uploaded.name,
          mime: uploaded.mime,
          url: uploaded.url,
          width: uploaded.width,
          height: uploaded.height,
          dataUrl: uploaded.dataUrl,
        }))
        .catch(() => updateAttachment(id, { status: 'error' }));
    });
  }, [updateAttachment]);

  const removeAttachment = useCallback((id: string) => {
    setAttachments((prev) => {
      const target = prev.find((item) => item.id === id);
      if (target) URL.revokeObjectURL(target.previewUrl);
      return prev.filter((item) => item.id !== id);
    });
  }, []);

  const clearAttachments = useCallback(() => {
    setAttachments((prev) => {
      prev.forEach((item) => URL.revokeObjectURL(item.previewUrl));
      return [];
    });
  }, []);

  const value = useMemo(() => ({
    draft,
    setDraft,
    textareaRef,
    focusComposer,
    populateDraft,
    applyTemplate,
    attachments,
    addFiles,
    removeAttachment,
    clearAttachments,
  }), [draft, focusComposer, populateDraft, applyTemplate, attachments, addFiles, removeAttachment, clearAttachments]);

  return (
    <ComposerContext.Provider value={value}>
      {children}
    </ComposerContext.Provider>
  );
}

const useComposerSelector = <T,>(selector: (state: ComposerContextProps) => T): T => (
  useContextSelector(ComposerContext, selector)
);

export const useComposerDraft = () => useComposerSelector(state => state.draft);
export const useSetComposerDraft = () => useComposerSelector(state => state.setDraft);
export const useComposerTextareaRef = () => useComposerSelector(state => state.textareaRef);
export const useFocusComposer = () => useComposerSelector(state => state.focusComposer);
export const usePopulateComposerDraft = () => useComposerSelector(state => state.populateDraft);
export const useApplyComposerTemplate = () => useComposerSelector(state => state.applyTemplate);
export const useComposerAttachments = () => useComposerSelector(state => state.attachments);
export const useAddComposerFiles = () => useComposerSelector(state => state.addFiles);
export const useRemoveComposerAttachment = () => useComposerSelector(state => state.removeAttachment);
export const useClearComposerAttachments = () => useComposerSelector(state => state.clearAttachments);
