import React, { useState, useEffect } from 'react';
import { Box, Text, useInput } from 'ink';
import Spinner from 'ink-spinner';
import fs from 'fs';
import path from 'path';
import { SearchResult } from '../types.js';
// @ts-ignore - JavaScript module
import { downloadBookSilent } from '../download.js';
// @ts-ignore - JavaScript module
import { sanitizeFilename, getBookGrabsDirectory } from '../utils.js';
// @ts-ignore - JavaScript module
import { cleanupFilename } from '../ai.js';

interface ResultsTableProps {
  results: SearchResult[];
  onBack: () => void;
}

export const ResultsTable: React.FC<ResultsTableProps> = ({ results, onBack }) => {
  const [selectedIndex, setSelectedIndex] = useState(0);
  const [currentPage, setCurrentPage] = useState(0);
  const [isDownloading, setIsDownloading] = useState(false);
  const [downloadMessage, setDownloadMessage] = useState('');
  const [downloadStatuses, setDownloadStatuses] = useState<Record<string, 'downloading' | 'success' | 'failed' | 'exists'>>({});
  const [downloadProgress, setDownloadProgress] = useState<Record<string, number>>({});
  const [abortController, setAbortController] = useState<AbortController | null>(null);
  
  // Check for existing files on component mount
  useEffect(() => {
    const checkExistingFiles = async () => {
      const statuses: Record<string, 'exists'> = {};
      
      for (const book of results) {
        try {
          const safeTitle = await cleanupFilename(book.title);
          const filename = `${safeTitle}.${book.ext}`;
          const bookGrabsDir = getBookGrabsDirectory();
          const authorDir = path.join(bookGrabsDir, sanitizeFilename(book.author));
          const filePath = path.join(authorDir, filename);
          
          if (fs.existsSync(filePath)) {
            statuses[book.md5] = 'exists';
          }
        } catch (error) {
          // Ignore errors when checking file existence
        }
      }
      
      setDownloadStatuses(statuses);
    };
    
    checkExistingFiles();
  }, [results]);

  // Clean up abort controller on unmount
  useEffect(() => {
    return () => {
      if (abortController) {
        abortController.abort();
      }
    };
  }, [abortController]);
  
  // Calculate items per page based on terminal height
  const terminalHeight = process.stdout.rows || 24; // Default to 24 if not available
  const headerLines = 3; // Title, page info, and some margin
  const footerLines = 2; // Instructions and margin
  const tableHeaderLines = 2; // Column headers with borders take 2 lines
  const paddingLines = 2; // Top and bottom padding
  
  // Each table row with borders actually takes about 3 lines
  const linesPerRow = 3;
  
  const availableLines = terminalHeight - headerLines - footerLines - tableHeaderLines - paddingLines;
  const itemsPerPage = Math.max(3, Math.floor(availableLines / linesPerRow));
  
  const totalPages = Math.ceil(results.length / itemsPerPage);
  const startIndex = currentPage * itemsPerPage;
  const endIndex = Math.min(startIndex + itemsPerPage, results.length);
  const currentPageResults = results.slice(startIndex, endIndex);
  
  // Calculate column widths
  const terminalWidth = process.stdout.columns || 100; // Default to 100 if not available
  const authorWidth = 20;
  const yearWidth = 6;
  const statusWidth = 12;
  const languageWidth = 4;
  const formatWidth = 6;
  const paddingAndBorders = 12; // Account for spaces and borders
  
  const titleWidth = Math.max(30, terminalWidth - authorWidth - yearWidth - statusWidth - languageWidth - formatWidth - paddingAndBorders);
  
  const truncateText = (text: string, maxLength: number) => {
    if (text.length <= maxLength) return text;
    return text.substring(0, maxLength - 3) + '...';
  };
  
  const getStatusColor = (status: string) => {
    switch (status) {
      case 'downloading':
        return 'yellow';
      case 'success':
        return 'green';
      case 'failed':
        return 'red';
      case 'exists':
        return 'gray';
      default:
        return 'white';
    }
  };
  
  const getStatusText = (md5: string) => {
    const status = downloadStatuses[md5];
    const progress = downloadProgress[md5] || 0;
    
    switch (status) {
      case 'downloading':
        return progress > 0 ? `${progress}%` : 'Downloading...';
      case 'success':
        return 'Downloaded';
      case 'failed':
        return 'Failed';
      case 'exists':
        return 'Exists';
      default:
        return 'Ready';
    }
  };

  const getStatusIndicator = (bookMd5: string) => {
    const status = downloadStatuses[bookMd5];
    const progress = downloadProgress[bookMd5] || 0;
    
    switch (status) {
      case 'downloading':
        if (progress > 0) {
          return { component: null, text: `[${progress}%] `, color: 'yellow' as const };
        }
        return { component: <Spinner type="dots" />, text: '  ', color: 'yellow' as const };
      case 'success':
        return { component: null, text: '[✓] ', color: 'green' as const };
      case 'failed':
        return { component: null, text: '[X] ', color: 'red' as const };
      case 'exists':
        return { component: null, text: '[≡] ', color: 'blue' as const };
      default:
        return { component: null, text: '[...] ', color: 'yellow' as const };
    }
  };

  const formatYear = (year: string) => {
    if (!year) return 'N/A';
    // Extract just the year part (first 4 digits) and truncate to fit column
    const cleanYear = year.match(/\d{4}/)?.[0] || year;
    return truncateText(cleanYear, yearWidth - 2);
  };

  const formatLanguage = (language: string) => {
    const lang = language || 'Unknown';
    return truncateText(lang, languageWidth - 2);
  };

  const titleTruncateLength = titleWidth - 3; // Account for potential ellipsis

  const handleDownload = async (book: SearchResult) => {
    // Check if file already exists
    if (downloadStatuses[book.md5] === 'exists') {
      setDownloadMessage(`File already exists: ${book.title}`);
      setTimeout(() => {
        setDownloadMessage('');
      }, 2000);
      return;
    }
    
    setIsDownloading(true);
    setDownloadMessage(`Downloading: ${book.title}...`);
    
    // Create new abort controller for this download
    const controller = new AbortController();
    setAbortController(controller);
    
    // Set status to downloading and reset progress
    setDownloadStatuses(prev => ({ ...prev, [book.md5]: 'downloading' }));
    setDownloadProgress(prev => ({ ...prev, [book.md5]: 0 }));
    
    try {
      const result = await (downloadBookSilent as any)(book, (progress: number) => {
        setDownloadProgress(prev => ({ ...prev, [book.md5]: progress }));
        setDownloadMessage(`Downloading: ${book.title}... ${progress}%`);
      }, controller.signal);
      
      if (result.success) {
        setDownloadStatuses(prev => ({ ...prev, [book.md5]: 'success' }));
        setDownloadProgress(prev => ({ ...prev, [book.md5]: 100 }));
        setDownloadMessage(`Downloaded successfully: ${book.title}`);
        setTimeout(() => {
          setDownloadMessage('');
          setIsDownloading(false);
        }, 2000);
      } else if ((result as any).alreadyExists) {
        setDownloadStatuses(prev => ({ ...prev, [book.md5]: 'exists' }));
        setDownloadMessage(`File already exists: ${book.title}`);
        setTimeout(() => {
          setDownloadMessage('');
          setIsDownloading(false);
        }, 2000);
      } else if (result.error === 'Operation cancelled') {
        setDownloadStatuses(prev => ({ ...prev, [book.md5]: 'failed' }));
        setDownloadMessage(`Download cancelled`);
        setTimeout(() => {
          setDownloadMessage('');
          setIsDownloading(false);
        }, 2000);
      } else {
        setDownloadStatuses(prev => ({ ...prev, [book.md5]: 'failed' }));
        setDownloadMessage(`Download failed: ${result.error}`);
        setTimeout(() => {
          setDownloadMessage('');
          setIsDownloading(false);
        }, 3000);
      }
    } catch (error) {
      setDownloadStatuses(prev => ({ ...prev, [book.md5]: 'failed' }));
      setDownloadMessage(`Download error: ${error instanceof Error ? error.message : 'Unknown error'}`);
      setTimeout(() => {
        setDownloadMessage('');
        setIsDownloading(false);
      }, 3000);
    } finally {
      setAbortController(null);
    }
  };

  const handleCancel = () => {
    if (isDownloading && abortController) {
      abortController.abort();
      setIsDownloading(false);
      setDownloadMessage('Cancelling download...');
      setTimeout(() => {
        setDownloadMessage('');
      }, 1000);
    }
  };

  useInput((input, key) => {
    if (key.escape) {
      if (isDownloading) {
        handleCancel();
      } else {
        onBack();
      }
    } else if (key.return) {
      if (results.length > 0 && !isDownloading) {
        const actualIndex = startIndex + selectedIndex;
        handleDownload(results[actualIndex]);
      }
    } else if (key.upArrow && !isDownloading) {
      if (selectedIndex > 0) {
        setSelectedIndex(selectedIndex - 1);
      } else if (currentPage > 0) {
        // Go to previous page and select the last item
        setCurrentPage(currentPage - 1);
        setSelectedIndex(itemsPerPage - 1);
      }
    } else if (key.downArrow && !isDownloading) {
      if (selectedIndex < currentPageResults.length - 1) {
        setSelectedIndex(selectedIndex + 1);
      } else if (currentPage < totalPages - 1) {
        // Go to next page and select the first item
        setCurrentPage(currentPage + 1);
        setSelectedIndex(0);
      }
    }
  });

  return (
    <Box flexDirection="column" padding={1}>
      <Box marginBottom={1} justifyContent="space-between">
        <Box>
          <Text bold color="blue">
            Search Results ({results.length} found)
          </Text>
          {totalPages > 1 && (
            <Text color="gray">
              {' '}[Page {currentPage + 1} of {totalPages}]
            </Text>
          )}
        </Box>
        
        {downloadMessage && (
          <Box>
            <Text color={downloadMessage.includes('successfully') ? 'green' : downloadMessage.includes('failed') || downloadMessage.includes('error') ? 'red' : 'yellow'}>
              {downloadMessage}
            </Text>
          </Box>
        )}
      </Box>
      
      {results.length === 0 ? (
        <Box flexDirection="column" alignItems="center" marginY={2}>
          <Text color="yellow">No results found.</Text>
          <Text color="gray">Try adjusting your search terms.</Text>
        </Box>
      ) : (
        <Box flexDirection="column">
          {/* Table Header */}
          <Box borderStyle="single" borderTop={true} borderBottom={true} paddingX={1}>
            <Box width={titleWidth}>
              <Text bold color="cyan">Title</Text>
            </Box>
            <Box width={authorWidth}>
              <Text bold color="cyan">Author</Text>
            </Box>
            <Box width={yearWidth}>
              <Text bold color="cyan">Year</Text>
            </Box>
            <Box width={formatWidth}>
              <Text bold color="cyan">Format</Text>
            </Box>
            <Box width={languageWidth}>
              <Text bold color="cyan">Lang</Text>
            </Box>
            <Box width={statusWidth}>
              <Text bold color="cyan">Status</Text>
            </Box>
          </Box>
          
          {/* Table Rows */}
          {currentPageResults.map((result, index) => {
            const statusIndicator = getStatusIndicator(result.md5);
            
            return (
              <Box 
                key={startIndex + index} 
                borderStyle="single" 
                borderBottom={true} 
                paddingX={1}
                borderColor={index === selectedIndex ? 'blue' : undefined}
              >
                <Box width={titleWidth}>
                  <Text color={index === selectedIndex ? 'white' : undefined}>
                    {truncateText(result.title, titleWidth - 2)}
                  </Text>
                </Box>
                <Box width={authorWidth}>
                  <Text color={index === selectedIndex ? 'white' : undefined}>
                    {truncateText(result.author, authorWidth - 2)}
                  </Text>
                </Box>
                <Box width={yearWidth}>
                  <Text color={index === selectedIndex ? 'white' : undefined}>
                    {formatYear(result.year)}
                  </Text>
                </Box>
                <Box width={formatWidth}>
                  <Text color={index === selectedIndex ? 'white' : 'green'}>
                    {truncateText(result.ext.toUpperCase(), formatWidth - 2)}
                  </Text>
                </Box>
                <Box width={languageWidth}>
                  <Text color={index === selectedIndex ? 'white' : undefined}>
                    {formatLanguage(result.language)}
                  </Text>
                </Box>
                <Box width={statusWidth}>
                  {statusIndicator.component && (
                    <Text color={statusIndicator.color}>
                      {statusIndicator.component}{statusIndicator.text}
                    </Text>
                  )}
                  {statusIndicator.text && !statusIndicator.component && (
                    <Text color={statusIndicator.color}>
                      {statusIndicator.text}
                    </Text>
                  )}
                </Box>
              </Box>
            );
          })}
        </Box>
      )}
      
      <Box marginTop={1}>
        <Text color="gray">
          {isDownloading 
            ? 'Downloading... Please wait' 
            : 'Use ↑/↓ to navigate, [Enter] to download, [Esc] to go back'
          }
        </Text>
        {!isDownloading && (
          <Text color="gray">
            Status: [≡] Already exists, [✓] Downloaded, [X] Failed, [...] Ready
          </Text>
        )}
      </Box>
    </Box>
  );
}; 