import React, { useEffect, useState, useRef, useCallback } from 'react';
import { useAuth } from './contexts/AuthContext';
import { useLanguage } from './contexts/LanguageContext';
import { uploadService } from './lib/uploadService';
import { FileRecord, RecognitionResult } from './types';
import { TaskStatus, TaskHistoryItem } from './types/api';
import LeftSidebar from './components/LeftSidebar';
import Navbar from './components/Navbar';
import FilePreview from './components/FilePreview';
import ResultPanel from './components/ResultPanel';
import UploadModal from './components/UploadModal';
import UserGuide from './components/UserGuide';

const PAGE_SIZE = 6;

function App() {
  const { user, initializing } = useAuth();
  const { t } = useLanguage();
  const [files, setFiles] = useState<FileRecord[]>([]);
  const [selectedFileId, setSelectedFileId] = useState<string | null>(null);
  const [selectedResult, setSelectedResult] = useState<RecognitionResult | null>(null);
  const [showUploadModal, setShowUploadModal] = useState(false);
  const [showUserGuide, setShowUserGuide] = useState(false);
  const [loading, setLoading] = useState(false);

  // Pagination state
  const [currentPage, setCurrentPage] = useState(1);
  const [hasMore, setHasMore] = useState(false);
  const [loadingMore, setLoadingMore] = useState(false);

  // Layout state
  const [sidebarWidth, setSidebarWidth] = useState(320);
  const [isResizing, setIsResizing] = useState(false);
  const [sidebarCollapsed, setSidebarCollapsed] = useState(false);
  const sidebarRef = useRef<HTMLDivElement>(null);

  // Polling intervals refs to clear them on unmount
  const pollingIntervals = useRef<Record<string, NodeJS.Timeout>>({});
  // Ref to track latest selectedFileId for use in polling callbacks (avoids stale closure)
  const selectedFileIdRef = useRef<string | null>(null);
  // Cache for recognition results (keyed by task_id/file_id)
  const resultsCache = useRef<Record<string, RecognitionResult>>({});
  // Ref to prevent double loading on mount (React 18 Strict Mode / dependency changes)
  const hasLoadedFiles = useRef(false);

  const selectedFile = files.find((f) => f.id === selectedFileId) || null;

  useEffect(() => {
    const handleStartGuide = () => setShowUserGuide(true);
    window.addEventListener('start-user-guide', handleStartGuide);

    // Check for first-time user
    const hasSeenGuide = localStorage.getItem('hasSeenGuide');
    if (!hasSeenGuide) {
      setTimeout(() => setShowUserGuide(true), 1500);
      localStorage.setItem('hasSeenGuide', 'true');
    }

    return () => window.removeEventListener('start-user-guide', handleStartGuide);
  }, []);

  useEffect(() => {
    if (!initializing && user && !hasLoadedFiles.current) {
      hasLoadedFiles.current = true;
      loadFiles();
    }
    // Reset when user logs out
    if (!user) {
      hasLoadedFiles.current = false;
      setFiles([]);
      setSelectedFileId(null);
      setCurrentPage(1);
      setHasMore(false);
    }
  }, [initializing, user]);

  useEffect(() => {
    // Keep ref in sync with state for polling callbacks
    selectedFileIdRef.current = selectedFileId;

    if (selectedFileId) {
      loadResult(selectedFileId);
    } else {
      setSelectedResult(null);
    }
  }, [selectedFileId]);

  // Cleanup polling on unmount
  useEffect(() => {
    return () => {
      Object.values(pollingIntervals.current).forEach(clearInterval);
      pollingIntervals.current = {};
    };
  }, []);

  useEffect(() => {
    const handlePaste = (e: ClipboardEvent) => {
      // If modal is open, let the modal handle paste events to avoid double upload
      if (showUploadModal) return;

      const items = e.clipboardData?.items;
      if (!items) return;

      const files: File[] = [];
      for (let i = 0; i < items.length; i++) {
        if (items[i].type.startsWith('image/') || items[i].type === 'application/pdf') {
          const file = items[i].getAsFile();
          if (file) files.push(file);
        }
      }

      if (files.length > 0) {
        handleUpload(files);
      }
    };

    document.addEventListener('paste', handlePaste);
    return () => document.removeEventListener('paste', handlePaste);
  }, [user, showUploadModal]);

  const startResizing = useCallback((mouseDownEvent: React.MouseEvent) => {
    mouseDownEvent.preventDefault();
    setIsResizing(true);
  }, []);

  const stopResizing = useCallback(() => {
    setIsResizing(false);
  }, []);

  const resize = useCallback(
    (mouseMoveEvent: MouseEvent) => {
      if (isResizing) {
        const newWidth = mouseMoveEvent.clientX;
        if (newWidth >= 280 && newWidth <= 400) {
          setSidebarWidth(newWidth);
        }
      }
    },
    [isResizing]
  );

  useEffect(() => {
    window.addEventListener('mousemove', resize);
    window.addEventListener('mouseup', stopResizing);
    return () => {
      window.removeEventListener('mousemove', resize);
      window.removeEventListener('mouseup', stopResizing);
    };
  }, [resize, stopResizing]);

  // Convert API TaskHistoryItem to internal FileRecord format
  const convertToFileRecord = (item: TaskHistoryItem): FileRecord => {
    // Map numeric status enum to internal string status
    const statusMap: Record<number, FileRecord['status']> = {
      [TaskStatus.Pending]: 'pending',
      [TaskStatus.Processing]: 'processing',
      [TaskStatus.Completed]: 'completed',
      [TaskStatus.Failed]: 'failed',
    };

    return {
      id: item.task_id,
      user_id: user?.id || null,
      filename: item.file_name,
      file_path: item.origin_url, // Already signed OSS URL for preview
      file_type: 'image/jpeg', // Default, could be derived from file_name
      file_size: 0, // Not provided by API
      thumbnail_path: null,
      status: statusMap[item.status] || 'pending',
      created_at: item.created_at,
      updated_at: item.created_at,
    };
  };

  // Convert API TaskHistoryItem to internal RecognitionResult format
  const convertToRecognitionResult = (item: TaskHistoryItem): RecognitionResult => {
    return {
      id: item.task_id,
      file_id: item.task_id,
      markdown_content: item.markdown,
      latex_content: item.latex,
      mathml_content: item.mathml,
      mml: item.mml,
      rendered_image_path: item.image_blob || null,
      created_at: item.created_at,
    };
  };

  const loadFiles = async () => {
    // Don't fetch if user is not logged in
    if (!user) return;

    setLoading(true);
    try {
      // Fetch first page only
      const data = await uploadService.getTaskList('FORMULA', 1, PAGE_SIZE);
      const taskList = data.task_list || [];
      const total = data.total || 0;

      // Update pagination state
      setCurrentPage(1);
      setHasMore(taskList.length < total);

      if (taskList.length > 0) {
        // Convert API data to internal format
        const fileRecords = taskList.map(convertToFileRecord);
        setFiles(fileRecords);

        // Cache all results from the history (they already contain full data)
        taskList.forEach(item => {
          if (item.status === TaskStatus.Completed) {
            resultsCache.current[item.task_id] = convertToRecognitionResult(item);
          }
        });

        // Auto-select first file if none selected
        if (!selectedFileId) {
          setSelectedFileId(fileRecords[0].id);
        }
      } else {
        setFiles([]);
      }
    } catch (error) {
      console.error('Error loading files:', error);
      setFiles([]);
    } finally {
      setLoading(false);
    }
  };

  const loadMoreFiles = async () => {
    // Don't fetch if user is not logged in or already loading
    if (!user || loadingMore || !hasMore) return;

    setLoadingMore(true);
    try {
      const nextPage = currentPage + 1;
      const data = await uploadService.getTaskList('FORMULA', nextPage, PAGE_SIZE);
      const taskList = data.task_list || [];
      const total = data.total || 0;

      if (taskList.length > 0) {
        const newFileRecords = taskList.map(convertToFileRecord);

        // Use functional update to get correct total count
        setFiles(prev => {
          const newFiles = [...prev, ...newFileRecords];
          // Check if there are more pages based on new total
          setHasMore(newFiles.length < total);
          return newFiles;
        });

        // Cache results
        taskList.forEach(item => {
          if (item.status === TaskStatus.Completed) {
            resultsCache.current[item.task_id] = convertToRecognitionResult(item);
          }
        });

        setCurrentPage(nextPage);
      } else {
        setHasMore(false);
      }
    } catch (error) {
      console.error('Error loading more files:', error);
    } finally {
      setLoadingMore(false);
    }
  };

  const loadResult = async (fileId: string) => {
    try {
      // First check the local cache (populated from history API)
      const cachedResult = resultsCache.current[fileId];
      if (cachedResult) {
        setSelectedResult(cachedResult);
        return;
      }

      // If not in cache, try to fetch from API (for tasks still processing)
      try {
        const result = await uploadService.getTaskResult(fileId);
        if (result.status === TaskStatus.Completed) {
          const recognitionResult: RecognitionResult = {
            id: fileId,
            file_id: fileId,
            markdown_content: result.markdown,
            latex_content: result.latex,
            mathml_content: result.mathml,
            mml: result.mml,
            rendered_image_path: result.image_blob || null,
            created_at: new Date().toISOString(),
          };
          resultsCache.current[fileId] = recognitionResult;
          setSelectedResult(recognitionResult);
        } else {
          setSelectedResult(null);
        }
      } catch {
        // Task might not exist or still processing
        setSelectedResult(null);
      }
    } catch (error) {
      console.error('Error loading result:', error);
      setSelectedResult(null);
    }
  };

  const startPolling = (taskNo: string, fileId: string) => {
    if (pollingIntervals.current[taskNo]) return;

    let attempts = 0;
    const maxAttempts = 30;

    pollingIntervals.current[taskNo] = setInterval(async () => {
      attempts++;

      try {
        const result = await uploadService.getTaskResult(taskNo);

        // Update status in file list
        setFiles(prevFiles => prevFiles.map(f => {
          if (f.id === fileId) {
            let status: FileRecord['status'] = 'processing';
            if (result.status === TaskStatus.Completed) status = 'completed';
            else if (result.status === TaskStatus.Failed) status = 'failed';

            return { ...f, status };
          }
          return f;
        }));

        if (result.status === TaskStatus.Completed || result.status === TaskStatus.Failed) {
          // Stop polling
          clearInterval(pollingIntervals.current[taskNo]);
          delete pollingIntervals.current[taskNo];

          if (result.status === TaskStatus.Completed) {
            // ... (keep existing completion logic)
            // Convert API result to internal RecognitionResult format
            const recognitionResult: RecognitionResult = {
              id: fileId,
              file_id: fileId,
              markdown_content: result.markdown,
              latex_content: result.latex,
              mathml_content: result.mathml,
              mml: result.mml,
              rendered_image_path: result.image_blob || null,
              created_at: new Date().toISOString()
            };

            // Cache the result for later retrieval
            resultsCache.current[fileId] = recognitionResult;

            // Update UI if this file is currently selected
            if (selectedFileIdRef.current === fileId) {
              setSelectedResult(recognitionResult);
            }
          }
        } else if (attempts >= maxAttempts) {
          // Timeout: Max attempts reached
          clearInterval(pollingIntervals.current[taskNo]);
          delete pollingIntervals.current[taskNo];

          // Mark as failed in UI
          setFiles(prevFiles => prevFiles.map(f => {
            if (f.id === fileId) {
              return { ...f, status: 'failed' };
            }
            return f;
          }));

          alert(t.alerts.taskTimeout);
        }

      } catch (error) {
        console.error('Polling error:', error);
        // Don't stop polling immediately on network error, but maybe counting errors?
        // For simplicity, keep polling until max attempts.
        if (attempts >= maxAttempts) {
          clearInterval(pollingIntervals.current[taskNo]);
          delete pollingIntervals.current[taskNo];
          setFiles(prevFiles => prevFiles.map(f => {
            if (f.id === fileId) return { ...f, status: 'failed' };
            return f;
          }));
          alert(t.alerts.networkError);
        }
      }
    }, 2000); // Poll every 2 seconds
  };

  const handleUpload = async (uploadFiles: File[]) => {
    setLoading(true);
    try {
      for (const file of uploadFiles) {
        // 1. Upload file to OSS (or check duplicate)
        const fileHash = await uploadService.calculateMD5(file);
        const signatureData = await uploadService.uploadFile(file);

        // 2. Create recognition task
        const taskData = await uploadService.createRecognitionTask(
          signatureData.path,
          fileHash,
          file.name
        );

        // Use task_no if available, or file ID from path, or fallback
        const fileId = taskData.task_no || crypto.randomUUID();

        const newFile: FileRecord = {
          id: fileId,
          user_id: user?.id || null,
          filename: file.name,
          // Use local object URL for immediate preview since OSS URL requires signing
          file_path: URL.createObjectURL(file),
          file_type: file.type,
          file_size: file.size,
          thumbnail_path: null,
          status: 'processing',
          created_at: new Date().toISOString(),
          updated_at: new Date().toISOString(),
        };

        // Add new file to the list (prepend)
        setFiles(prevFiles => [newFile, ...prevFiles]);
        setSelectedFileId(newFile.id);

        // Start polling for this task
        if (taskData.task_no) {
          startPolling(taskData.task_no, fileId);
        }
      }
    } catch (error) {
      console.error('Error uploading files:', error);
      alert(`${t.alerts.uploadFailed}: ` + (error instanceof Error ? error.message : 'Unknown error'));
    } finally {
      setLoading(false);
    }
  };

  if (initializing) {
    return (
      <div className="min-h-screen bg-gray-50 flex items-center justify-center">
        <div className="text-center">
          <div className="w-16 h-16 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
          <p className="text-gray-600">{t.common.loading}</p>
        </div>
      </div>
    );
  }

  return (
    <div className="h-screen flex flex-col bg-gray-50 font-sans text-gray-900 overflow-hidden">
      <Navbar />
      <div className="flex-1 flex overflow-hidden">
        {/* Left Sidebar */}
        <div
          ref={sidebarRef}
          className="flex-shrink-0 bg-white border-r border-gray-200 relative transition-all duration-300 ease-in-out"
          style={{ width: sidebarCollapsed ? 64 : sidebarWidth }}
        >
          <LeftSidebar
            files={files}
            selectedFileId={selectedFileId}
            onFileSelect={setSelectedFileId}
            onUploadClick={() => setShowUploadModal(true)}
            isCollapsed={sidebarCollapsed}
            onToggleCollapse={() => setSidebarCollapsed(!sidebarCollapsed)}
            onUploadFiles={handleUpload}
            hasMore={hasMore}
            loadingMore={loadingMore}
            onLoadMore={loadMoreFiles}
          />

          {/* Resize Handle */}
          {!sidebarCollapsed && (
            <div
              className="absolute right-0 top-0 w-1 h-full cursor-col-resize hover:bg-blue-400 z-50 opacity-0 hover:opacity-100 transition-opacity"
              onMouseDown={startResizing}
            />
          )}
        </div>

        {/* Middle Content: File Preview */}
        <div className="flex-1 flex min-w-0 flex-col bg-gray-100/50">
          <FilePreview file={selectedFile} />
        </div>

        {/* Right Result: Recognition Result */}
        <div className="flex-1 flex min-w-0 flex-col bg-white">
          <ResultPanel
            result={selectedResult}
            fileStatus={selectedFile?.status}
          />
        </div>

        {showUploadModal && (
          <UploadModal
            onClose={() => setShowUploadModal(false)}
            onUpload={handleUpload}
          />
        )}

        <UserGuide
          isOpen={showUserGuide}
          onClose={() => setShowUserGuide(false)}
        />

        {loading && (
          <div className="fixed inset-0 bg-black bg-opacity-30 flex items-center justify-center z-50">
            <div className="bg-white rounded-xl shadow-xl p-8">
              <div className="w-16 h-16 border-4 border-blue-600 border-t-transparent rounded-full animate-spin mx-auto mb-4"></div>
              <p className="text-gray-900 font-medium">{t.common.processing}</p>
            </div>
          </div>
        )}
      </div>

      {/* ICP Footer */}
      <div className="flex-shrink-0 bg-white border-t border-gray-200 py-2 px-4 text-center">
        <a
          href="https://beian.miit.gov.cn"
          target="_blank"
          rel="noopener noreferrer"
          className="text-xs text-gray-500 hover:text-gray-700 transition-colors"
        >
          京ICP备2025152973号
        </a>
      </div>
    </div>
  );
}

export default App;
