import { useState, useRef, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import {
  apiDownloaderDownloadRetrieve,
} from '@/api/generated/public/downloader';
import { type VideoInfoResponse } from '@/api/generated/public/models';
import { FaLink, FaVideo, FaVolumeUp, FaFile, FaFont, FaCookie } from 'react-icons/fa';
import Ad from './Ad';
import Statistics from './Statistics';
import { publicApi } from '@/api/publicClient';

// Common file extensions supported by ffmpeg
const FILE_EXTENSIONS = [
  { value: 'mp4', label: 'MP4 (H.264 + AAC, most compatible)' },
  { value: 'mkv', label: 'MKV (Flexible, lossless container)' },
  { value: 'webm', label: 'WebM (VP9/AV1 + Opus)' },
  { value: 'avi', label: 'AVI (Older format)' },
  { value: 'mov', label: 'MOV (Apple-friendly)' },
  { value: 'flv', label: 'FLV (Legacy)' },
  { value: 'ogg', label: 'OGG (Audio/Video)' },
];

export default function Downloader() {
  const { t } = useTranslation('downloader');

  const [videoUrl, setVideoUrl] = useState('');
  const [videoInfo, setVideoInfo] = useState<null | VideoInfoResponse>(null);
  const [isLoading, setIsLoading] = useState(false);
  const [isDownloading, setIsDownloading] = useState(false);
  const [downloadStatus, setDownloadStatus] = useState<string>('');
  const [downloadProgress, setDownloadProgress] = useState<number | null>(null);
  const [error, setError] = useState<null | { error: string }>(null);
  const wsRef = useRef<WebSocket | null>(null);

  // Basic download options
  const [selectedVideoQuality, setSelectedVideoQuality] = useState<string>('');
  const [selectedAudioQuality, setSelectedAudioQuality] = useState<string>('');
  const [selectedExtension, setSelectedExtension] = useState<string>('mp4');

  // Playlist selection
  const [selectedVideos, setSelectedVideos] = useState<number[]>([]);

  // Advanced options
  const [subtitles, setSubtitles] = useState<string>('');
  const [embedSubtitles, setEmbedSubtitles] = useState<boolean>(false);
  const [embedThumbnail, setEmbedThumbnail] = useState<boolean>(false);
  const [cookies, setCookies] = useState<string>('');
  const [showAdvanced, setShowAdvanced] = useState<boolean>(false);

  // Helper functions for playlist selection
  const toggleVideoSelection = (videoIndex: number) => {
    setSelectedVideos(prev =>
      prev.includes(videoIndex)
        ? prev.filter(i => i !== videoIndex)
        : [...prev, videoIndex]
    );
  };

  const selectAllVideos = () => {
    if (videoInfo?.videos) {
      setSelectedVideos(videoInfo.videos.map((_, index) => index + 1));
    }
  };

  const deselectAllVideos = () => {
    setSelectedVideos([]);
  };

  // Cleanup WebSocket on unmount
  useEffect(() => {
    return () => {
      if (wsRef.current) {
        wsRef.current.close();
      }
    };
  }, []);

  const getAllVideoQualities = () => {
    if (!videoInfo?.videos) return [];
    const allQualities = new Set<string>();
    videoInfo.videos.forEach(video => {
      video.video_resolutions.forEach(quality => allQualities.add(quality));
    });
    return Array.from(allQualities).sort((a, b) => {
      const aNum = parseInt(a.replace('p', ''));
      const bNum = parseInt(b.replace('p', ''));
      return bNum - aNum;
    });
  };

  const getAllAudioQualities = () => {
    if (!videoInfo?.videos) return [];
    const allQualities = new Set<string>();
    videoInfo.videos.forEach(video => {
      video.audio_resolutions.forEach(quality => allQualities.add(quality));
    });
    return Array.from(allQualities).sort((a, b) => {
      const aNum = parseInt(a.replace('kbps', ''));
      const bNum = parseInt(b.replace('kbps', ''));
      return bNum - aNum;
    });
  };

  const getSubtitleLanguages = () => {
    if (!videoInfo?.videos) return [];
    const allLangs = new Set<string>();
    videoInfo.videos.forEach(video => {
      video.subtitle_languages.forEach(lang => allLangs.add(lang));
    });
    return Array.from(allLangs).sort();
  };

  const videoHasSubtitles = videoInfo?.videos.some(v => v.has_subtitles) ?? false;
  const videoHasThumbnail = videoInfo?.videos.some(v => v.thumbnail !== null) ?? false;

  async function retrieveVideoInfo() {
    setIsLoading(true);
    setError(null);
    setVideoInfo(null);
    setSelectedVideos([]);
    try {
      const info = await apiDownloaderDownloadRetrieve({ url: videoUrl });
      setVideoInfo(info);
      // If it's a playlist, select all videos by default
      if (info.is_playlist && info.videos) {
        setSelectedVideos(info.videos.map((_, index) => index + 1));
      }
    } catch (err: any) {
      const errorMessage = err.response?.data?.error || err.message;
      setError({ error: errorMessage });
      console.error('Retrieve video info error:', err);
    } finally {
      setIsLoading(false);
    }
  }

  async function handleDownload() {
    if (!videoUrl) {
      setError({ error: t('pleaseEnterUrl') });
      return;
    }

    setIsDownloading(true);
    setDownloadStatus(t('connectingStatus'));
    setDownloadProgress(null);
    setError(null);

    try {
      const videoQuality = selectedVideoQuality
        ? parseInt(selectedVideoQuality.replace('p', ''))
        : undefined;
      const audioQuality = selectedAudioQuality
        ? parseInt(selectedAudioQuality.replace('kbps', ''))
        : undefined;

      // Connect to WebSocket
      const wsUrl = `ws://localhost:8000/ws/downloader/`;
      const ws = new WebSocket(wsUrl);
      wsRef.current = ws;

      await new Promise<void>((resolve, reject) => {
        ws.onopen = () => {
          setDownloadStatus(t('startingStatus'));
          // Send download parameters
          ws.send(JSON.stringify({
            url: videoUrl,
            ext: selectedExtension,
            video_quality: videoQuality,
            audio_quality: audioQuality,
            selected_videos: videoInfo?.is_playlist && selectedVideos.length > 0 ? selectedVideos : null,
            subtitles: subtitles || null,
            embed_subtitles: embedSubtitles,
            embed_thumbnail: embedThumbnail,
            cookies: cookies || null,
          }));
        };

        ws.onmessage = (event) => {
          const data = JSON.parse(event.data);
          if (data.type === 'status') {
            setDownloadStatus(data.message);
          } else if (data.type === 'progress') {
            setDownloadStatus(data.message);
            setDownloadProgress(data.percent);
          } else if (data.type === 'done') {
            setDownloadStatus(t('finalizing'));
            setDownloadProgress(100);

            publicApi.post('/api/downloader/download/file/',
              { token: data.token },
              { responseType: 'blob' }
            )
            .then((response) => {
              const url = window.URL.createObjectURL(new Blob([response.data]));
              let filename = data.filename || `video.${selectedExtension}`;
              const link = document.createElement('a');
              link.href = url;
              link.setAttribute('download', filename);
              document.body.appendChild(link);
              link.click();
              link.remove();
              window.URL.revokeObjectURL(url);
              setDownloadStatus(t('downloadComplete'));
              resolve();
            })
            .catch((err) => {
              console.error('Failed to download blob:', err);
              reject(new Error('Failed to retrieve the file after processing.'));
            });

          } else if (data.type === 'error') {
            reject(new Error(data.message));
          }
        };

        ws.onerror = () => {
          reject(new Error('WebSocket connection failed'));
        };

        ws.onclose = () => {
          if (wsRef.current === ws) {
            wsRef.current = null;
          }
        };
      });

    } catch (err: any) {
      const errorMessage = err.message || 'Failed to download video';
      setError({ error: errorMessage });
    } finally {
      if (wsRef.current) {
        wsRef.current.close();
        wsRef.current = null;
      }
      setIsDownloading(false);
      setDownloadStatus('');
      setDownloadProgress(null);
    }
  }

  return (
    <div className="p-8 w-full max-w-4xl mx-auto">
      <Ad />
      <h1 className="text-2xl font-bold mb-6">{t('title')}</h1>

      <div className="mb-6">
        <div className="flex items-center gap-2 mb-3">
          <FaLink className="text-gray-500" />
          <span className="text-sm font-medium">{t('urlLabel')}</span>
        </div>
        <input
          type="text"
          value={videoUrl}
          onChange={(e) => setVideoUrl(e.target.value)}
          placeholder={t('urlPlaceholder')}
          className="w-full p-3 border rounded"
        />
      </div>

      <button
        onClick={retrieveVideoInfo}
        disabled={isLoading || !videoUrl}
        className="px-6 py-3 bg-blue-500 text-white rounded hover:bg-blue-600 disabled:bg-gray-300 disabled:cursor-not-allowed mx-2 mb-4"
      >
        {isLoading ? t('loading') : t('retrieveOptions')}
      </button>

      {error && (
        <div className="mt-6 mx-4 p-4 bg-red-100 text-red-700 rounded">
          {t('error')}: {error.error}
        </div>
      )}

      {videoInfo && (
        <div className="mt-8 mx-4 p-6 border rounded">
          {videoInfo.is_playlist ? (
            <div>
              <h2 className="text-xl font-semibold mb-4">
                📋 {videoInfo.playlist_title || t('playlist')}
              </h2>
              <p className="text-gray-600 mb-6">
                {t('videosFound', { count: videoInfo.playlist_count })}
              </p>

              {/* Playlist Video Selection */}
              <div className="mb-6">
                <div className="flex items-center gap-4 mb-3">
                  <h3 className="text-lg font-medium">{t('selectVideos')}</h3>
                  <div className="flex gap-2">
                    <button
                      onClick={selectAllVideos}
                      className="px-3 py-1 text-sm bg-blue-100 text-blue-700 rounded hover:bg-blue-200"
                    >
                      {t('selectAll')}
                    </button>
                    <button
                      onClick={deselectAllVideos}
                      className="px-3 py-1 text-sm bg-gray-100 text-gray-700 rounded hover:bg-gray-200"
                    >
                      {t('clearAll')}
                    </button>
                  </div>
                </div>

                <div className="max-h-96 overflow-y-auto border rounded">
                  {videoInfo.videos.map((video, index) => {
                    const videoNumber = index + 1;
                    return (
                      <div key={video.id} className="p-3 border-b last:border-b-0 hover:bg-gray-50">
                        <label className="flex items-start gap-3 cursor-pointer">
                          <input
                            type="checkbox"
                            checked={selectedVideos.includes(videoNumber)}
                            onChange={() => toggleVideoSelection(videoNumber)}
                            className="mt-1 w-4 h-4"
                          />
                          <div className="flex gap-3 flex-1">
                            {video.thumbnail && (
                              <img
                                src={video.thumbnail}
                                alt={video.title}
                                className="w-20 h-15 object-cover rounded flex-shrink-0"
                              />
                            )}
                            <div className="flex-1">
                              <div className="font-medium">
                                {videoNumber}. {video.title}
                              </div>
                              {video.duration && (
                                <div className="text-sm text-gray-600">
                                  {t('duration')}: {Math.floor(video.duration / 60)}:{String(video.duration % 60).padStart(2, '0')}
                                </div>
                              )}
                              <div className="text-xs text-gray-500 mt-1">
                                {t('quality')}: {video.video_resolutions.join(', ') || 'N/A'} |
                                {t('audio')}: {video.audio_resolutions.join(', ') || 'N/A'}
                              </div>
                            </div>
                          </div>
                        </label>
                      </div>
                    );
                  })}
                </div>

                <div className="mt-3 text-sm text-gray-600">
                  {t('selected', { selected: selectedVideos.length, total: videoInfo.videos.length })}
                </div>
              </div>
            </div>
          ) : (
            <div>
              <h2 className="text-xl font-semibold mb-4">
                🎥 {videoInfo.videos[0]?.title || 'Video'}
              </h2>

              {videoInfo.videos[0]?.thumbnail && (
                <img
                  src={videoInfo.videos[0].thumbnail}
                  alt={videoInfo.videos[0].title}
                  className="mt-4 w-1/3 max-w-sm rounded shadow mx-auto block"
                />
              )}

              {videoInfo.videos[0]?.duration && (
                <p className="mt-4 text-gray-600 text-center">
                  {t('duration')}: {Math.floor(videoInfo.videos[0].duration / 60)}:{String(videoInfo.videos[0].duration % 60).padStart(2, '0')}
                </p>
              )}
            </div>
          )}

          {/* Quality and Format Selection */}
          <div className="mt-8 mx-2 grid grid-cols-1 md:grid-cols-3 gap-6">
            {/* Video Quality Dropdown */}
            <div>
              <label className="block text-sm font-medium mb-2 flex items-center gap-2">
                <FaVideo className="text-gray-500" />
                {t('videoQuality')}
              </label>
              <select
                value={selectedVideoQuality}
                onChange={(e) => setSelectedVideoQuality(e.target.value)}
                className="w-full p-2 border rounded"
              >
                <option value="">{t('bestAvailable')}</option>
                {getAllVideoQualities().map((res) => (
                  <option key={res} value={res}>{res}</option>
                ))}
              </select>
            </div>

            {/* Audio Quality Dropdown */}
            <div>
              <label className="block text-sm font-medium mb-2 flex items-center gap-2">
                <FaVolumeUp className="text-gray-500" />
                {t('audioQuality')}
              </label>
              <select
                value={selectedAudioQuality}
                onChange={(e) => setSelectedAudioQuality(e.target.value)}
                className="w-full p-2 border rounded"
              >
                <option value="">{t('bestAvailable')}</option>
                {getAllAudioQualities().map((res) => (
                  <option key={res} value={res}>{res}</option>
                ))}
              </select>
            </div>

            {/* File Extension Dropdown */}
            <div>
              <label className="block text-sm font-medium mb-2 flex items-center gap-2">
                <FaFile className="text-gray-500" />
                {t('fileFormat')}
              </label>
              <select
                value={selectedExtension}
                onChange={(e) => setSelectedExtension(e.target.value)}
                className="w-full p-2 border rounded"
              >
                {FILE_EXTENSIONS.map((ext) => (
                  <option key={ext.value} value={ext.value}>
                    {ext.label}
                  </option>
                ))}
              </select>
            </div>
          </div>

          <button
            onClick={handleDownload}
            disabled={isDownloading || (videoInfo.is_playlist && selectedVideos.length === 0)}
            className="mt-8 mx-2 px-6 py-3 bg-green-500 text-white rounded hover:bg-green-600 disabled:bg-gray-300 disabled:cursor-not-allowed"
          >
            {isDownloading ? downloadStatus || t('downloading') : (
              videoInfo.is_playlist
                ? t('downloadSelected', { count: selectedVideos.length })
                : t('download')
            )}
          </button>

          {isDownloading && downloadStatus && (
            <div className="mt-3 mx-2">
              <div className="flex items-center gap-2 text-sm text-blue-600 mb-2">
                <svg className="animate-spin h-4 w-4" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24">
                  <circle className="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" strokeWidth="4"/>
                  <path className="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8v8z"/>
                </svg>
                {downloadStatus}
              </div>
              {downloadProgress !== null && (
                <div className="w-full bg-gray-200 rounded-full h-2">
                  <div
                    className="bg-blue-600 h-2 rounded-full transition-all duration-300"
                    style={{ width: `${downloadProgress}%` }}
                  />
                </div>
              )}
            </div>
          )}

          {videoInfo.is_playlist && selectedVideos.length === 0 && (
            <p className="mt-4 mx-2 text-sm text-red-600">
              {t('pleaseSelectVideo')}
            </p>
          )}

          {/* Advanced Options Toggle */}
          <div className="mt-10 mx-2 border-t pt-8">
            <button
              onClick={() => setShowAdvanced(!showAdvanced)}
              className="text-blue-500 hover:text-blue-700 font-medium flex items-center gap-2 mx-2"
            >
              {showAdvanced ? '▼' : '▶'} {t('advancedOptions')}
            </button>

            {showAdvanced && (
              <div className="mt-6 space-y-6 p-6 rounded mx-2">
                {/* Subtitles */}
                <div>
                  <label className="block text-sm font-medium mb-2 flex items-center gap-2">
                    <FaFont className="text-gray-500" />
                    {t('subtitles')}
                    {!videoHasSubtitles && <span className="text-gray-400 font-normal text-xs">{t('subtitlesNotAvailable')}</span>}
                  </label>
                  {(() => {
                    const subtitleLanguages = getSubtitleLanguages();
                    if (subtitleLanguages.length > 0) {
                      return (
                        <>
                          <select
                            value={subtitles}
                            onChange={(e) => setSubtitles(e.target.value)}
                            className="w-full p-2 border rounded"
                          >
                            <option value="">{t('noSubtitles')}</option>
                            <option value="all">{t('allAvailable')}</option>
                            {subtitleLanguages.map(lang => (
                              <option key={lang} value={lang}>{lang}</option>
                            ))}
                          </select>
                          <p className="text-xs text-gray-500 mt-1">
                            {t('subtitleLangsAvailable', { count: subtitleLanguages.length })}
                          </p>
                        </>
                      );
                    }
                    return (
                      <>
                        <input
                          type="text"
                          value={subtitles}
                          onChange={(e) => setSubtitles(e.target.value)}
                          placeholder={videoHasSubtitles ? "e.g., 'en', 'en,cs', or 'all'" : t('noSubtitlesAvailable')}
                          disabled={!videoHasSubtitles}
                          className={`w-full p-2 border rounded ${!videoHasSubtitles ? 'opacity-50 cursor-not-allowed bg-gray-100' : ''}`}
                        />
                        {videoHasSubtitles && (
                          <p className="text-xs text-gray-500 mt-1">
                            {t('autoCaptionsHint')}
                          </p>
                        )}
                      </>
                    );
                  })()}
                </div>

                {/* Checkboxes Row */}
                <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
                  {(() => {
                    const embedSubsDisabled = !subtitles || !['mkv', 'mp4'].includes(selectedExtension);
                    return (
                      <label className={`flex items-center gap-2 ${embedSubsDisabled ? 'opacity-50' : ''}`}>
                        <input
                          type="checkbox"
                          checked={embedSubtitles}
                          onChange={(e) => setEmbedSubtitles(e.target.checked)}
                          disabled={embedSubsDisabled}
                          className="w-4 h-4"
                        />
                        <span className="text-sm">
                          {t('embedSubtitles')}
                          {!['mkv', 'mp4'].includes(selectedExtension)
                            ? <span className="text-xs text-gray-400"> {t('embedSubtitlesMkvMp4Only')}</span>
                            : !subtitles
                            ? <span className="text-xs text-gray-400"> {t('embedSubtitlesSelectFirst')}</span>
                            : null}
                        </span>
                      </label>
                    );
                  })()}

                  <label className={`flex items-center gap-2 ${!videoHasThumbnail ? 'opacity-50' : ''}`}>
                    <input
                      type="checkbox"
                      checked={embedThumbnail}
                      onChange={(e) => setEmbedThumbnail(e.target.checked)}
                      disabled={!videoHasThumbnail}
                      className="w-4 h-4"
                    />
                    <span className="text-sm">
                      {t('embedThumbnail')}
                      {!videoHasThumbnail && <span className="text-xs text-gray-400"> {t('noThumbnailAvailable')}</span>}
                    </span>
                  </label>
                </div>

                {/* Cookies for Age-Restricted Content */}
                <div>
                  <label className="block text-sm font-medium mb-2 flex items-center gap-2">
                    <FaCookie className="text-gray-500" />
                    {t('cookies')}
                  </label>
                  <textarea
                    value={cookies}
                    onChange={(e) => setCookies(e.target.value)}
                    placeholder={t('cookiesPlaceholder')}
                    rows={4}
                    className="w-full p-2 border rounded font-mono text-xs"
                  />
                  <p className="text-xs text-gray-500 mt-1">
                    {t('cookiesHint')}
                  </p>
                </div>
              </div>
            )}
          </div>
        </div>
      )}

      <Statistics />
    </div>
  );
}
