'use client';

import { useState, useEffect } from 'react';
import { useRouter, useSearchParams } from 'next/navigation';
import { toast } from 'react-hot-toast';
import { Film, Download, Sparkles, FolderOpen, X, Loader2 } from 'lucide-react';
import FileUpload from '@/components/FileUpload';
import JobProgress from '@/components/JobProgress';
import AssetLibrary from '@/components/AssetLibrary';
import ProviderControls from '@/components/ProviderControls';
import { modulesApi, assetsApi, capabilitiesApi } from '@/lib/api';
import { useStore } from '@/lib/store';
import { ProviderConfig } from '@/types/providers';

export default function VideoGeneratePage() {
  const router = useRouter();
  const searchParams = useSearchParams();
  const { addJob, updateJob } = useStore();

  // Provider config state
  const [capabilities, setCapabilities] = useState<Record<string, ProviderConfig> | null>(null);
  const [loadingCapabilities, setLoadingCapabilities] = useState(true);

  // Basic state
  const [mode, setMode] = useState<'text' | 'image'>('text');
  const [prompt, setPrompt] = useState('');
  const [provider, setProvider] = useState('runway');
  const [model, setModel] = useState('');
  const [providerOptions, setProviderOptions] = useState<Record<string, any>>({});

  // Input image state
  const [file, setFile] = useState<File | null>(null);
  const [assetId, setAssetId] = useState<string | null>(null);
  const [uploading, setUploading] = useState(false);

  // Veo frame control (special feature)
  const [firstFrameAssetId, setFirstFrameAssetId] = useState<string | null>(null);
  const [lastFrameAssetId, setLastFrameAssetId] = useState<string | null>(null);
  const [referenceAssetIds, setReferenceAssetIds] = useState<string[]>([]);
  const [firstFramePreview, setFirstFramePreview] = useState<string | null>(null);
  const [lastFramePreview, setLastFramePreview] = useState<string | null>(null);
  const [referencePreviews, setReferencePreviews] = useState<string[]>([]);
  const [inputPreview, setInputPreview] = useState<string | null>(null);
  const [inputFilename, setInputFilename] = useState<string | null>(null);

  // Asset library modal
  const [showAssetLibrary, setShowAssetLibrary] = useState(false);
  const [assetSelectTarget, setAssetSelectTarget] = useState<'input' | 'first' | 'last' | 'reference'>('input');

  // Results
  const [jobId, setJobId] = useState<string | null>(null);
  const [generatedVideo, setGeneratedVideo] = useState<any>(null);
  const [loading, setLoading] = useState(false);

  // Load provider capabilities on mount
  useEffect(() => {
    const loadCapabilities = async () => {
      try {
        const response = await capabilitiesApi.getVideoProviders();
        setCapabilities(response.data);

        // Set default provider and model
        const firstProvider = Object.keys(response.data)[0];
        setProvider(firstProvider);
        setModel(response.data[firstProvider].defaultModel);

        // Initialize with default values
        initializeDefaults(response.data[firstProvider]);
      } catch (err) {
        console.error('Failed to load provider configurations:', err);
        toast.error('Failed to load provider configurations');
      } finally {
        setLoadingCapabilities(false);
      }
    };

    loadCapabilities();
    loadCapabilities();
  }, []);

  // Handle URL params
  useEffect(() => {
    const urlAssetId = searchParams.get('assetId');
    if (urlAssetId) {
      setMode('image');
      setAssetId(urlAssetId);
      // Optionally fetch asset details here if needed to show filename context
    }

    const urlPrompt = searchParams.get('prompt');
    if (urlPrompt) {
      setPrompt(urlPrompt);
    }
  }, [searchParams]);

  // Initialize default values for provider
  const initializeDefaults = (config: ProviderConfig) => {
    if (!config) {
      console.error('Config is undefined');
      return;
    }

    const defaults: Record<string, any> = {};

    // Common controls
    if (config.commonControls && Array.isArray(config.commonControls)) {
      config.commonControls.forEach((control) => {
        defaults[control.name] = control.default;
      });
    }

    // Model-specific controls
    const modelConfig = config.models?.find(m => m.id === config.defaultModel);
    if (modelConfig?.controls && Array.isArray(modelConfig.controls)) {
      modelConfig.controls.forEach((control) => {
        defaults[control.name] = control.default;
      });
    }

    setProviderOptions(defaults);
  };

  // Handle provider change
  const handleProviderChange = (newProvider: string) => {
    if (!capabilities) return;

    setProvider(newProvider);
    const config = capabilities[newProvider];
    setModel(config.defaultModel);
    initializeDefaults(config);
  };

  // Handle model change
  const handleModelChange = (newModel: string) => {
    setModel(newModel);

    if (!capabilities) return;
    const config = capabilities[provider];
    const modelConfig = config.models.find(m => m.id === newModel);

    // Merge current options with model defaults
    const modelDefaults: Record<string, any> = {};
    modelConfig?.controls?.forEach((control) => {
      if (!(control.name in providerOptions)) {
        modelDefaults[control.name] = control.default;
      }
    });

    setProviderOptions({
      ...providerOptions,
      ...modelDefaults
    });
  };

  const handleFileUpload = async (uploadedFile: File) => {
    setFile(uploadedFile);
    setUploading(true);

    try {
      const response = await assetsApi.upload(uploadedFile);
      setAssetId(response.data.id);
      toast.success('Image uploaded!');
    } catch (err: any) {
      if (err.response?.status === 409) {
        const existingAssetId = err.response.data.detail.asset_id;
        const shouldOverwrite = window.confirm(
          `File "${uploadedFile.name}" already exists. \nClick OK to Overwrite, Cancel to Use Existing.`
        );

        if (shouldOverwrite) {
          try {
            const response = await assetsApi.upload(uploadedFile, undefined, false, true); // overwrite=true
            setAssetId(response.data.id);
            toast.success('Image overwritten!');
          } catch (retryErr: any) {
            toast.error('Failed to overwrite image');
            setFile(null);
          }
        } else {
          setAssetId(existingAssetId);
          toast('Using existing file', { icon: 'ℹ️' });
        }
      } else {
        toast.error('Failed to upload image');
        setFile(null);
      }
    } finally {
      setUploading(false);
    }
  };

  const handleAssetSelect = (asset: any) => {
    const thumbnailUrl = asset.thumbnail_url
      ? `${process.env.NEXT_PUBLIC_API_URL}${asset.thumbnail_url}`
      : null;

    switch (assetSelectTarget) {
      case 'input':
        setAssetId(asset.id);
        setInputPreview(thumbnailUrl || `/api/v1/assets/${asset.id}/download`);
        setInputFilename(asset.original_filename || asset.filename);
        setFile(null);
        break;
      case 'first':
        setFirstFrameAssetId(asset.id);
        setFirstFramePreview(thumbnailUrl || `/api/v1/assets/${asset.id}/download`);
        break;
      case 'last':
        setLastFrameAssetId(asset.id);
        setLastFramePreview(thumbnailUrl || `/api/v1/assets/${asset.id}/download`);
        break;
      case 'reference':
        if (referenceAssetIds.length < 4) {
          setReferenceAssetIds([...referenceAssetIds, asset.id]);
          // We need previews for these too, but state is currently just IDs.
          // Let's assume we change referenceAssetIds to objects or fetch thumbnails?
          // For simplicity, we can fetch asset details or we just add the URL to a separate state?
          // Better: Change referenceAssetIds to referenceAssets state array of objects {id, url}
          // But refactoring minimal: Let's use a parallel state `referencePreviews`.
          setReferencePreviews(prev => [...prev, thumbnailUrl || `/api/v1/assets/${asset.id}/download`]);
        }
        break;
    }
    setShowAssetLibrary(false);
  };

  const openAssetLibrary = (target: 'input' | 'first' | 'last' | 'reference') => {
    setAssetSelectTarget(target);
    setShowAssetLibrary(true);
  };

  const handleGenerate = async () => {
    if (mode === 'text' && !prompt.trim()) {
      toast.error('Please enter a prompt');
      return;
    }
    if (mode === 'image' && !assetId) {
      toast.error('Please upload or select an image');
      return;
    }

    setLoading(true);
    setGeneratedVideo(null);

    try {
      const payload: any = {
        prompt: prompt || undefined,
        provider,
        model,
        provider_options: providerOptions,
        input_asset_id: mode === 'image' ? assetId : undefined,
      };

      // Veo-specific frame controls
      if (provider === 'veo') {
        if (firstFrameAssetId) {
          payload.first_frame_asset_id = firstFrameAssetId;
        }
        if (lastFrameAssetId) {
          payload.last_frame_asset_id = lastFrameAssetId;
        }
        if (referenceAssetIds.length > 0) {
          payload.reference_asset_ids = referenceAssetIds;
        }
      }

      const response = await modulesApi.generateVideo(payload);

      const job = response.data;
      setJobId(job.id);
      addJob({
        id: job.id,
        module: 'video_generation',
        status: job.status,
        progress: job.progress,
        created_at: job.created_at,
      });

      toast.success('Video generation started!');
    } catch (err: any) {
      console.error('Generation error:', err);
      toast.error(err.response?.data?.detail || 'Failed to start generation');
      setLoading(false);
    }
  };

  const handleJobComplete = async (job: any) => {
    setLoading(false);
    updateJob(job.id, { status: 'completed', progress: 100 });

    if (job.output_asset_ids?.[0]) {
      const asset = await assetsApi.get(job.output_asset_ids[0]);
      setGeneratedVideo(asset.data);
      toast.success('Video generated successfully!');
    }
  };

  const handleJobError = (error: string) => {
    setLoading(false);
    toast.error(error);
  };

  const handleDownload = async () => {
    if (!generatedVideo) return;
    try {
      const response = await assetsApi.download(generatedVideo.id);
      const url = window.URL.createObjectURL(response.data);
      const a = document.createElement('a');
      a.href = url;
      a.download = generatedVideo.original_filename;
      a.click();
      window.URL.revokeObjectURL(url);
    } catch (err) {
      toast.error('Failed to download video');
    }
  };

  if (loadingCapabilities) {
    return (
      <div className="flex items-center justify-center min-h-screen">
        <Loader2 className="w-8 h-8 animate-spin text-forge-yellow" />
      </div>
    );
  }

  const currentConfig = capabilities?.[provider];

  return (
    <div className="max-w-6xl mx-auto space-y-8">
      <div className="flex items-center gap-4">
        <div className="w-12 h-12 bg-forge-yellow/10 rounded-lg flex items-center justify-center">
          <Film className="w-6 h-6 text-forge-yellow" />
        </div>
        <div>
          <h1 className="text-2xl font-bold text-white">Video Generator</h1>
          <p className="text-gray-500">Create videos with Runway Gen-3/4 and Google Veo 3.1</p>
        </div>
      </div>

      <div className="grid grid-cols-1 lg:grid-cols-2 gap-8">
        {/* Controls */}
        <div className="space-y-6">
          {/* Mode Toggle */}
          <div>
            <label className="block text-sm font-medium text-gray-300 mb-2">Generation Mode</label>
            <div className="flex gap-2">
              <button
                onClick={() => setMode('text')}
                className={`flex-1 px-4 py-3 rounded-lg font-medium transition-colors ${mode === 'text'
                  ? 'bg-forge-yellow text-black'
                  : 'bg-forge-dark border border-gray-700 text-gray-300 hover:border-gray-600'
                  }`}
              >
                Text to Video
              </button>
              <button
                onClick={() => setMode('image')}
                className={`flex-1 px-4 py-3 rounded-lg font-medium transition-colors ${mode === 'image'
                  ? 'bg-forge-yellow text-black'
                  : 'bg-forge-dark border border-gray-700 text-gray-300 hover:border-gray-600'
                  }`}
              >
                Image to Video
              </button>
            </div>
          </div>

          {/* Prompt */}
          <div>
            <label className="block text-sm font-medium text-gray-300 mb-2">
              {mode === 'text' ? 'Prompt' : 'Motion Prompt (Optional)'}
            </label>
            <textarea
              value={prompt}
              onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => setPrompt(e.target.value)}
              placeholder={mode === 'text' ? 'Describe the video you want to create...' : 'Describe how the image should animate...'}
              className="input-field min-h-[100px] resize-none"
            />
          </div>

          {/* Image Upload (for image mode) */}
          {mode === 'image' && (
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">Source Image</label>
              <div className="flex gap-2 mb-2">
                <button
                  onClick={() => openAssetLibrary('input')}
                  className="flex items-center gap-2 px-4 py-2 bg-forge-gray border border-gray-700 rounded-lg text-gray-300 hover:border-forge-yellow transition-colors"
                >
                  <FolderOpen className="w-4 h-4" />
                  My Files
                </button>
              </div>
              <FileUpload
                onUpload={handleFileUpload}
                accept={{ 'image/*': ['.png', '.jpg', '.jpeg', '.webp'] }}
                currentFile={file}
                onClear={() => {
                  setFile(null);
                  setAssetId(null);
                }}
                label="Or upload a new image"
              />
              {uploading && <p className="mt-2 text-sm text-forge-yellow">Uploading...</p>}
              {assetId && inputPreview && !file && (
                <div className="mt-2 bg-forge-dark border border-gray-700 rounded-lg p-2 flex gap-3 items-center">
                  <div className="w-12 h-12 bg-black/50 rounded overflow-hidden flex-shrink-0">
                    <img src={inputPreview} alt="Selected" className="w-full h-full object-cover" />
                  </div>
                  <div className="flex-1 min-w-0">
                    <p className="text-sm font-medium text-white truncate">{inputFilename || 'Selected Asset'}</p>
                    <p className="text-xs text-green-400">Selected from My Files</p>
                  </div>
                  <button onClick={() => { setAssetId(null); setInputPreview(null); setInputFilename(null); }} className="p-1 hover:text-white"><X className="w-4 h-4" /></button>
                </div>
              )}
            </div>
          )}

          {/* Provider & Model */}
          <div className="grid grid-cols-2 gap-4">
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">Provider</label>
              <select
                value={provider}
                onChange={(e: React.ChangeEvent<HTMLSelectElement>) => handleProviderChange(e.target.value)}
                className="select-field"
              >
                {capabilities && Object.entries(capabilities).map(([id, config]) => (
                  <option key={id} value={id}>
                    {config.name}
                  </option>
                ))}
              </select>
            </div>
            <div>
              <label className="block text-sm font-medium text-gray-300 mb-2">Model</label>
              <select
                value={model}
                onChange={(e: React.ChangeEvent<HTMLSelectElement>) => handleModelChange(e.target.value)}
                className="select-field"
              >
                {currentConfig?.models.map((m) => (
                  <option key={m.id} value={m.id}>
                    {m.name}
                  </option>
                ))}
              </select>
            </div>
          </div>

          {/* Model Description */}
          {currentConfig?.models.find(m => m.id === model)?.description && (
            <p className="text-xs text-gray-500 -mt-4">
              {currentConfig.models.find(m => m.id === model)?.description}
            </p>
          )}

          {/* Dynamic Provider Controls */}
          {currentConfig && (
            <div className="bg-forge-gray rounded-lg p-4">
              <ProviderControls
                config={currentConfig}
                selectedModel={model}
                values={providerOptions}
                onChange={setProviderOptions}
              />
            </div>
          )}

          {/* Veo Frame Control (Special Feature) */}
          {provider === 'veo' && (
            <div className="bg-forge-gray rounded-lg p-4 space-y-4">
              <h3 className="text-sm font-medium text-gray-300">Advanced Frame Control</h3>

              <div className="grid grid-cols-2 gap-4">
                <div>
                  <label className="block text-xs text-gray-500 mb-2">First Frame</label>
                  <button
                    onClick={() => openAssetLibrary('first')}
                    onDragOver={(e) => e.preventDefault()}
                    onDrop={(e) => {
                      e.preventDefault();
                      try {
                        const data = JSON.parse(e.dataTransfer.getData('application/json'));
                        if (data.type === 'forge-asset') {
                          setFirstFrameAssetId(data.id);
                          setFirstFramePreview(data.url); // Use URL from drag data for immediate preview
                        }
                      } catch (err) {
                        console.error('Invalid drop data', err);
                      }
                    }}
                    className="w-full aspect-video bg-forge-dark border border-gray-700 rounded-lg flex items-center justify-center hover:border-forge-yellow transition-colors overflow-hidden"
                  >
                    {firstFramePreview ? (
                      <div className="relative w-full h-full">
                        <img src={firstFramePreview} alt="First frame" className="w-full h-full object-cover" />
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            setFirstFrameAssetId(null);
                            setFirstFramePreview(null);
                          }}
                          className="absolute top-1 right-1 p-1 bg-black/50 rounded"
                        >
                          <X className="w-3 h-3 text-white" />
                        </button>
                      </div>
                    ) : (
                      <div className="flex flex-col items-center gap-2 text-gray-500">
                        <FolderOpen className="w-5 h-5" />
                        <span className="text-xs">Select or Drop Frame</span>
                      </div>
                    )}
                  </button>
                </div>

                <div>
                  <label className="block text-xs text-gray-500 mb-2">Last Frame</label>
                  <button
                    onClick={() => openAssetLibrary('last')}
                    onDragOver={(e) => e.preventDefault()}
                    onDrop={(e) => {
                      e.preventDefault();
                      try {
                        const data = JSON.parse(e.dataTransfer.getData('application/json'));
                        if (data.type === 'forge-asset') {
                          setLastFrameAssetId(data.id);
                          setLastFramePreview(data.url);
                        }
                      } catch (err) {
                        console.error('Invalid drop data', err);
                      }
                    }}
                    className="w-full aspect-video bg-forge-dark border border-gray-700 rounded-lg flex items-center justify-center hover:border-forge-yellow transition-colors overflow-hidden"
                  >
                    {lastFramePreview ? (
                      <div className="relative w-full h-full">
                        <img src={lastFramePreview} alt="Last frame" className="w-full h-full object-cover" />
                        <button
                          onClick={(e) => {
                            e.stopPropagation();
                            setLastFrameAssetId(null);
                            setLastFramePreview(null);
                          }}
                          className="absolute top-1 right-1 p-1 bg-black/50 rounded"
                        >
                          <X className="w-3 h-3 text-white" />
                        </button>
                      </div>
                    ) : (
                      <div className="flex flex-col items-center gap-2 text-gray-500">
                        <FolderOpen className="w-5 h-5" />
                        <span className="text-xs">Select or Drop Frame</span>
                      </div>
                    )}
                  </button>
                </div>
              </div>

              <div>
                <label className="block text-xs text-gray-500 mb-2">
                  Reference Images ({referenceAssetIds.length}/4)
                </label>
                <div
                  onDragOver={(e) => e.preventDefault()}
                  onDrop={(e) => {
                    e.preventDefault();
                    if (referenceAssetIds.length >= 4) return;
                    try {
                      const data = JSON.parse(e.dataTransfer.getData('application/json'));
                      if (data.type === 'forge-asset') {
                        setReferenceAssetIds(prev => [...prev, data.id]);
                        setReferencePreviews(prev => [...prev, data.url]);
                      }
                    } catch (err) {
                      console.error('Invalid drop data', err);
                    }
                  }}
                >
                  <button
                    onClick={() => openAssetLibrary('reference')}
                    disabled={referenceAssetIds.length >= 4}
                    className="w-full px-4 py-2 bg-forge-dark border border-gray-700 rounded-lg text-sm text-gray-300 hover:border-forge-yellow transition-colors disabled:opacity-50 disabled:cursor-not-allowed border-dashed"
                  >
                    Add or Drop Reference Image
                  </button>
                </div>
                {referenceAssetIds.length > 0 && (
                  <div className="flex gap-2 mt-2 flex-wrap">
                    {referenceAssetIds.map((id, index) => (
                      <div key={`${id}-${index}`} className="relative w-16 h-16 bg-forge-dark border border-gray-700 rounded overflow-hidden">
                        {referencePreviews[index] && <img src={referencePreviews[index]} className="w-full h-full object-cover" />}
                        <button
                          onClick={() => {
                            setReferenceAssetIds(referenceAssetIds.filter((_, i) => i !== index));
                            setReferencePreviews(referencePreviews.filter((_, i) => i !== index));
                          }}
                          className="absolute -top-1 -right-1 p-0.5 bg-red-500 rounded-full z-10"
                        >
                          <X className="w-3 h-3 text-white" />
                        </button>
                        <span className="absolute inset-0 flex items-center justify-center text-xs text-white font-bold drop-shadow-md pointer-events-none">
                          {index + 1}
                        </span>
                      </div>
                    ))}
                  </div>
                )}
              </div>
            </div>
          )}

          {/* Generate Button */}
          <button
            onClick={handleGenerate}
            disabled={loading || (mode === 'text' ? !prompt.trim() : !assetId)}
            className="btn-primary w-full flex items-center justify-center gap-2 disabled:opacity-50 disabled:cursor-not-allowed"
          >
            <Sparkles className="w-5 h-5" />
            {loading ? 'Generating...' : 'Generate Video'}
          </button>

          {/* Job Progress */}
          {jobId && loading && (
            <JobProgress
              jobId={jobId}
              onComplete={handleJobComplete}
              onError={handleJobError}
            />
          )}
        </div>

        {/* Results */}
        <div>
          <h2 className="text-lg font-semibold text-white mb-4">Generated Video</h2>
          {generatedVideo ? (
            <div className="space-y-4">
              <div className="bg-forge-dark rounded-xl overflow-hidden border border-gray-800">
                <video
                  src={`/api/v1/assets/${generatedVideo.id}/download`}
                  controls
                  className="w-full"
                />
              </div>
              <button
                onClick={handleDownload}
                className="btn-primary w-full flex items-center justify-center gap-2"
              >
                <Download className="w-4 h-4" />
                Download Video
              </button>
            </div>
          ) : (
            <div className="bg-forge-dark rounded-xl border border-gray-800 aspect-video flex items-center justify-center">
              <p className="text-gray-500">Generated video will appear here</p>
            </div>
          )}
        </div>
      </div>

      {/* Asset Library Modal */}
      <AssetLibrary
        isOpen={showAssetLibrary}
        onSelect={handleAssetSelect}
        onClose={() => setShowAssetLibrary(false)}
        fileTypes={['image']}
        title="Select Image"
      />
    </div>
  );
}
