import { useState, useEffect } from 'react';
import type { ReactNode } from 'react';
import { useFilesAPI } from '../../hooks/useFilesAPI';
import { useFilesRefresh } from '../../channels';
import { toast } from 'sonner';
import { getFileType } from './file-types';
import { FileViewerContext } from './FileViewerContext';

type FileViewerProviderProps = {
  filePath: string;
  fileName: string;
  root?: string;
  content?: string;
  onOpenFile?: (filePath: string, root: string) => void;
  onReplaceView?: (viewPath: string, viewRoot: string, ephemeralPath: string, ephemeralRoot: string) => void;
  autoPlay?: boolean;
  children: ReactNode;
};

export const FileViewerProvider = ({
  filePath,
  fileName,
  root = 'home',
  content: directContent,
  onOpenFile,
  onReplaceView,
  autoPlay = false,
  children,
}: FileViewerProviderProps) => {
  const [content, setContent] = useState<string | null>(directContent ?? null);
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [ttsLoading, setTtsLoading] = useState(false);
  const [ocrLoading, setOcrLoading] = useState(false);
  const [transcribeLoading, setTranscribeLoading] = useState(false);
  const [extractAudioLoading, setExtractAudioLoading] = useState(false);
  const [extractLoading, setExtractLoading] = useState(false);
  const [saveResultLoading, setSaveResultLoading] = useState(false);
  const [editing, setEditing] = useState(false);
  const files = useFilesAPI(root);
  const [, bumpFilesRefresh] = useFilesRefresh();
  const fileType = getFileType(fileName);
  const editable = fileType === 'markdown' || fileType === 'code' || fileType === 'text';

  useEffect(() => {
    if (directContent !== undefined) {
      setContent(directContent);
      setLoading(false);
      return;
    }

    if (fileType === 'audio' || fileType === 'video' || fileType === 'image' || fileType === 'pdf' || fileType === 'archive') {
      setLoading(false);
      return;
    }

    setLoading(true);
    setError(null);
    files
      .readFile(filePath)
      .then((res) => setContent(res.content))
      .catch(() => setError('Failed to read file'))
      .finally(() => setLoading(false));
  }, [filePath, directContent]);

  const handleDownload = () => {
    const a = document.createElement('a');
    a.href = files.getRawUrl(filePath);
    a.download = fileName;
    a.click();
  };

  const handleReadAloud = async () => {
    setTtsLoading(true);
    try {
      const { audioPath, audioRoot } = await files.tts(filePath, { saveNextTo: true });
      bumpFilesRefresh();
      onReplaceView?.(filePath, root, audioPath, audioRoot);
    } catch {
      toast.error('Failed to generate speech audio');
    } finally {
      setTtsLoading(false);
    }
  };

  const handleOcr = async () => {
    setOcrLoading(true);
    try {
      const { ocrPath, ocrRoot } = await files.ocr(filePath, { saveNextTo: true });
      bumpFilesRefresh();
      onReplaceView?.(filePath, root, ocrPath, ocrRoot);
    } catch {
      toast.error('Failed to extract text from image');
    } finally {
      setOcrLoading(false);
    }
  };

  const handleTranscribe = async () => {
    setTranscribeLoading(true);
    try {
      const { transcriptionPath, transcriptionRoot } = await files.transcribe(filePath, { saveNextTo: true });
      bumpFilesRefresh();
      onReplaceView?.(filePath, root, transcriptionPath, transcriptionRoot);
    } catch {
      toast.error('Failed to transcribe audio');
    } finally {
      setTranscribeLoading(false);
    }
  };

  const handleExtractAudio = async () => {
    setExtractAudioLoading(true);
    try {
      const { audioPath, audioRoot } = await files.extractAudio(filePath);
      onOpenFile?.(audioPath, audioRoot);
    } catch {
      toast.error('Failed to extract audio from video');
    } finally {
      setExtractAudioLoading(false);
    }
  };

  const isCachedResult = root === 'user-data' && filePath.startsWith('cache/');

  const handleSaveResult = isCachedResult
    ? async () => {
        setSaveResultLoading(true);
        try {
          const { savedPath } = await files.saveResult(filePath);
          const savedName = savedPath.split('/').pop() ?? savedPath;
          bumpFilesRefresh();
          toast.success(`Saved as "${savedName}"`);
        } catch {
          toast.error('Failed to save file');
        } finally {
          setSaveResultLoading(false);
        }
      }
    : null;

  const handleExtract = async () => {
    setExtractLoading(true);
    try {
      const { extractedPath } = await files.extract(filePath);
      const folderName = extractedPath.split('/').pop() ?? extractedPath;
      toast.success(`Extracted to "${folderName}"`);
    } catch {
      toast.error('Failed to extract archive');
    } finally {
      setExtractLoading(false);
    }
  };

  return (
    <FileViewerContext
      value={{
        filePath,
        fileName,
        root,
        fileType,
        content,
        loading,
        error,
        directContent: directContent !== undefined,
        ttsLoading,
        ocrLoading,
        transcribeLoading,
        extractAudioLoading,
        extractLoading,
        autoPlay,
        editable,
        editing,
        setEditing,
        setContent,
        handleReadAloud,
        handleOcr,
        handleTranscribe,
        handleExtractAudio,
        handleExtract,
        handleDownload,
        handleSaveResult,
        saveResultLoading,
      }}
    >
      {children}
    </FileViewerContext>
  );
};
