'use client';

import { useState, useEffect, useRef } from 'react';
import { X, FileText, Download, Copy, Search, ChevronUp, ChevronDown } from 'lucide-react';
import { createPortal } from 'react-dom';

interface TextFile {
  id: number;
  title: string;
  path: string;
  size: number;
  type: string;
}

interface FileSystemItem {
  name: string;
  path: string;
  isDirectory: boolean;
  size: number;
  thumbnail?: string;
  type?: string;
  id?: number;
}

interface TextViewerProps {
  text: TextFile | FileSystemItem;
  isOpen: boolean;
  onClose: () => void;
  formatFileSize?: (bytes: number) => string;
}

export default function TextViewer({
  text,
  isOpen,
  onClose,
  formatFileSize
}: TextViewerProps) {
  const [content, setContent] = useState<string>('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string>('');
  const [searchTerm, setSearchTerm] = useState('');
  const [currentSearchIndex, setCurrentSearchIndex] = useState(-1);
  const [searchResults, setSearchResults] = useState<number[]>([]);
  const [fontSize, setFontSize] = useState(14);
  const [showLineNumbers, setShowLineNumbers] = useState(true);
  const [wordWrap, setWordWrap] = useState(true);
  const [selectedEncoding, setSelectedEncoding] = useState<string>('utf8');
  const [availableEncodings] = useState<string[]>(['utf8', 'gbk', 'gb2312', 'big5', 'latin1']);
  const contentRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    if (isOpen && text) {
      loadTextContent();
    }
  }, [isOpen, text, selectedEncoding]);

  const loadTextContent = async () => {
    if (!text || !('id' in text) || !text.id) {
      setError('Invalid text file');
      return;
    }

    setLoading(true);
    setError('');
    setContent('');

    try {
      const response = await fetch(`/api/texts/${text.id}?encoding=${selectedEncoding}`);
      if (!response.ok) {
        throw new Error('Failed to load text file');
      }
      const data = await response.json();
      
      // Handle base64 encoded content
      if (data.encoding === 'base64') {
        try {
          const decodedContent = atob(data.content);
          setContent(decodedContent);
        } catch (err) {
          setError('Failed to decode file content');
        }
      } else {
        setContent(data.content || '');
      }
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Failed to load text file');
    } finally {
      setLoading(false);
    }
  };

  const handleSearch = (term: string) => {
    setSearchTerm(term);
    if (!term.trim()) {
      setSearchResults([]);
      setCurrentSearchIndex(-1);
      return;
    }

    const lines = content.split('\n');
    const results: number[] = [];
    
    lines.forEach((line, index) => {
      if (line.toLowerCase().includes(term.toLowerCase())) {
        results.push(index);
      }
    });

    setSearchResults(results);
    setCurrentSearchIndex(results.length > 0 ? 0 : -1);
  };

  const navigateSearch = (direction: 'next' | 'prev') => {
    if (searchResults.length === 0) return;

    if (direction === 'next') {
      setCurrentSearchIndex((prev) => (prev + 1) % searchResults.length);
    } else {
      setCurrentSearchIndex((prev) => (prev - 1 + searchResults.length) % searchResults.length);
    }
  };

  const copyToClipboard = async () => {
    try {
      await navigator.clipboard.writeText(content);
    } catch (err) {
      console.error('Failed to copy to clipboard:', err);
    }
  };

  const downloadFile = () => {
    const blob = new Blob([content], { type: 'text/plain' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = ('name' in text ? text.name : text.title) || 'text.txt';
    document.body.appendChild(a);
    a.click();
    document.body.removeChild(a);
    URL.revokeObjectURL(url);
  };

  const getTextTitle = () => {
    if ('name' in text) return text.name;
    if ('title' in text) return text.title;
    return 'Text File';
  };

  const getTextSize = () => {
    if (!text) return '0 Bytes';
    if (formatFileSize) {
      return formatFileSize(text.size);
    }
    const bytes = text.size;
    if (bytes === 0) return '0 Bytes';
    const k = 1024;
    const sizes = ['Bytes', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  };

  const formatContent = () => {
    if (!content) return [];
    
    const lines = content.split('\n');
    return lines.map((line, index) => ({
      lineNumber: index + 1,
      content: line,
      isHighlighted: searchResults.includes(index)
    }));
  };

  const scrollToLine = (lineNumber: number) => {
    const element = document.getElementById(`line-${lineNumber}`);
    if (element) {
      element.scrollIntoView({ behavior: 'smooth', block: 'center' });
    }
  };

  useEffect(() => {
    if (currentSearchIndex >= 0 && searchResults.length > 0) {
      const lineNumber = searchResults[currentSearchIndex] + 1;
      scrollToLine(lineNumber);
    }
  }, [currentSearchIndex, searchResults]);

  // Keyboard shortcuts
  useEffect(() => {
    if (!isOpen) return;

    const handleKeyDown = (e: KeyboardEvent) => {
      if (e.ctrlKey || e.metaKey) {
        switch (e.key) {
          case 'f':
            e.preventDefault();
            const searchInput = document.getElementById('text-search') as HTMLInputElement;
            searchInput?.focus();
            break;
          case 'c':
            if (e.shiftKey) {
              e.preventDefault();
              copyToClipboard();
            }
            break;
          case 's':
            e.preventDefault();
            downloadFile();
            break;
        }
      } else {
        switch (e.key) {
          case 'Escape':
            e.preventDefault();
            onClose();
            break;
          case 'F3':
            e.preventDefault();
            if (e.shiftKey) {
              navigateSearch('prev');
            } else {
              navigateSearch('next');
            }
            break;
        }
      }
    };

    window.addEventListener('keydown', handleKeyDown);
    return () => window.removeEventListener('keydown', handleKeyDown);
  }, [isOpen, onClose, searchResults, currentSearchIndex]);

  if (!isOpen || typeof window === 'undefined') return null;

  const formattedLines = formatContent();

  return createPortal(
    <div className="fixed inset-0 bg-black/90 z-50 flex items-center justify-center p-4">
      <div className="relative w-full max-w-7xl h-[95vh] bg-zinc-900 rounded-xl border border-zinc-800 flex flex-col">
        {/* Header */}
        <div className="flex items-center justify-between p-4 border-b border-zinc-800 flex-shrink-0">
          <div className="flex items-center gap-3">
            <FileText className="h-5 w-5 text-blue-500" />
            <div>
              <h2 className="text-lg font-semibold text-white">{getTextTitle()}</h2>
              <p className="text-sm text-zinc-400">{getTextSize()}</p>
            </div>
          </div>
          
          <div className="flex items-center gap-2">
            {/* Search */}
            <div className="relative">
              <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 h-4 w-4 text-zinc-400" />
              <input
                id="text-search"
                type="text"
                placeholder="Search in text..."
                value={searchTerm}
                onChange={(e) => handleSearch(e.target.value)}
                className="pl-10 pr-8 py-2 bg-zinc-800 border border-zinc-700 rounded-lg text-white text-sm focus:outline-none focus:ring-2 focus:ring-blue-500"
              />
              {searchResults.length > 0 && (
                <span className="absolute right-2 top-1/2 transform -translate-y-1/2 text-xs text-zinc-400">
                  {currentSearchIndex + 1}/{searchResults.length}
                </span>
              )}
            </div>
            
            {/* Search Navigation */}
            {searchResults.length > 0 && (
              <div className="flex items-center gap-1">
                <button
                  onClick={() => navigateSearch('prev')}
                  className="p-1 text-zinc-400 hover:text-white transition-colors"
                  title="Previous match (Shift+F3)"
                >
                  <ChevronUp className="h-4 w-4" />
                </button>
                <button
                  onClick={() => navigateSearch('next')}
                  className="p-1 text-zinc-400 hover:text-white transition-colors"
                  title="Next match (F3)"
                >
                  <ChevronDown className="h-4 w-4" />
                </button>
              </div>
            )}

            {/* Actions */}
            <button
              onClick={copyToClipboard}
              className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors"
              title="Copy to clipboard (Ctrl+Shift+C)"
            >
              <Copy className="h-4 w-4" />
            </button>
            
            <button
              onClick={downloadFile}
              className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors"
              title="Download file (Ctrl+S)"
            >
              <Download className="h-4 w-4" />
            </button>

            <button
              onClick={onClose}
              className="p-2 text-zinc-400 hover:text-white hover:bg-zinc-800 rounded-lg transition-colors"
            >
              <X className="h-5 w-5" />
            </button>
          </div>
        </div>

        {/* Toolbar */}
        <div className="flex items-center justify-between p-3 border-b border-zinc-800 bg-zinc-800/50 flex-shrink-0">
          <div className="flex items-center gap-4">
            <div className="flex items-center gap-2">
              <label className="text-sm text-zinc-300">Font Size:</label>
              <select
                value={fontSize}
                onChange={(e) => setFontSize(Number(e.target.value))}
                className="bg-zinc-700 border border-zinc-600 rounded px-2 py-1 text-white text-sm"
              >
                <option value={12}>12px</option>
                <option value={14}>14px</option>
                <option value={16}>16px</option>
                <option value={18}>18px</option>
                <option value={20}>20px</option>
              </select>
            </div>

            <div className="flex items-center gap-2">
              <label className="text-sm text-zinc-300">Encoding:</label>
              <select
                value={selectedEncoding}
                onChange={(e) => setSelectedEncoding(e.target.value)}
                className="bg-zinc-700 border border-zinc-600 rounded px-2 py-1 text-white text-sm"
              >
                {availableEncodings.map((encoding) => (
                  <option key={encoding} value={encoding}>
                    {encoding.toUpperCase()}
                  </option>
                ))}
              </select>
              <span className="text-xs text-zinc-400 ml-1">
                {selectedEncoding === 'utf8' ? '(Default)' : 
                 selectedEncoding === 'gbk' || selectedEncoding === 'gb2312' ? '(Chinese)' : 
                 selectedEncoding === 'big5' ? '(Traditional Chinese)' : '(Other)'}
              </span>
            </div>

            <label className="flex items-center gap-2 text-sm text-zinc-300">
              <input
                type="checkbox"
                checked={showLineNumbers}
                onChange={(e) => setShowLineNumbers(e.target.checked)}
                className="rounded"
              />
              Line Numbers
            </label>

            <label className="flex items-center gap-2 text-sm text-zinc-300">
              <input
                type="checkbox"
                checked={wordWrap}
                onChange={(e) => setWordWrap(e.target.checked)}
                className="rounded"
              />
              Word Wrap
            </label>
          </div>

          <div className="text-sm text-zinc-400">
            {formattedLines.length} lines
          </div>
        </div>

        {/* Content */}
        <div className="flex-1 overflow-hidden min-h-0">
          {loading ? (
            <div className="flex items-center justify-center h-full">
              <div className="text-zinc-400">Loading...</div>
            </div>
          ) : error ? (
            <div className="flex items-center justify-center h-full">
              <div className="text-red-400">{error}</div>
            </div>
          ) : (
            <div 
              ref={contentRef}
              className="h-full overflow-auto p-4 custom-scrollbar"
              style={{ fontSize: `${fontSize}px` }}
            >
              <div className={`font-mono text-zinc-300 ${wordWrap ? 'whitespace-pre-wrap' : 'whitespace-pre'}`}>
                {formattedLines.map(({ lineNumber, content, isHighlighted }) => (
                  <div
                    key={lineNumber}
                    id={`line-${lineNumber}`}
                    className={`flex ${isHighlighted ? 'bg-yellow-500/20' : ''}`}
                  >
                    {showLineNumbers && (
                      <div className="text-zinc-500 pr-4 select-none min-w-[60px] text-right">
                        {lineNumber}
                      </div>
                    )}
                    <div className="flex-1 break-words">
                      {content || ' '}
                    </div>
                  </div>
                ))}
              </div>
            </div>
          )}
        </div>
      </div>
    </div>,
    document.body
  );
}
