// SRT import/export panel + Auto-Captions (Whisper AI).

'use client';

import { useRef, useState } from 'react';
import { Subtitles, FileUp, Sparkles, Loader2, Languages, FileVideo, Palette, RotateCcw } from 'lucide-react';
import { useEditor } from '@/store/editor';
import { parseSrt, formatTimeShort } from '@/lib/media';
import { Section } from './FormFields';
import { formatSrtTime } from './FormFields';
import { generateCaptions, type CaptionProgress, type WhisperModelSize } from '@/lib/captions/whisper';
import { extractAudioFromVideo } from '@/lib/ffmpeg';
import { DEFAULT_SUBTITLE_STYLE, type SubtitlePosition, type SubtitleStyle } from '@/types';

export function SubtitleProperties() {
  const setSubtitles = useEditor((s) => s.setSubtitles);
  const subtitles = useEditor((s) => s.subtitles);
  const currentTime = useEditor((s) => s.currentTime);
  const setToast = useEditor((s) => s.setToast);
  const assets = useEditor((s) => s.assets);
  const selection = useEditor((s) => s.selection);
  const subtitleStyle = useEditor((s) => s.subtitleStyle);
  const setSubtitleStyle = useEditor((s) => s.setSubtitleStyle);

  const srtInputRef = useRef<HTMLInputElement | null>(null);
  const [autoBusy, setAutoBusy] = useState(false);
  const [autoPct, setAutoPct] = useState(0);
  const [autoMsg, setAutoMsg] = useState('');
  const [autoLang, setAutoLang] = useState<'th' | 'en' | 'auto'>('th');
  const [autoModel, setAutoModel] = useState<WhisperModelSize>('tiny');

  function onProgress(p: CaptionProgress) {
    setAutoPct(p.pct);
    setAutoMsg(p.message);
  }

  async function runAutoCaptions() {
    if (autoBusy) return;
    // Pick a target: selected asset first, then audio asset, then video asset.
    // Video assets work too — we'll extract their built-in audio track via
    // FFmpeg.wasm (so the user doesn't have to import a separate audio file).
    let target = assets.find((a) => a.id === selection.clipId) ?? null;
    if (!target || (target.kind !== 'audio' && target.kind !== 'video')) {
      target = assets.find((a) => a.kind === 'audio') ?? null;
    }
    if (!target) target = assets.find((a) => a.kind === 'video') ?? null;
    if (!target) {
      setToast({ message: 'ต้องมีวิดีโอหรือเสียงในไลบรารีก่อน', level: 'error' });
      return;
    }
    setAutoBusy(true);
    setAutoPct(0);
    setAutoMsg('กำลังเริ่มต้น...');
    try {
      let audioBuffer = target.audioBuffer;
      if (!audioBuffer && target.kind === 'video') {
        setAutoMsg('กำลัง extract เสียงจากวิดีโอ...');
        setAutoPct(8);
        try {
          const resp = await fetch(target.url);
          const blob = await resp.blob();
          const file = new File([blob], target.name, { type: blob.type || 'video/mp4' });
          const extracted = await extractAudioFromVideo(file, (m) => {
            // Suppress noisy ffmpeg logs but keep errors visible.
            if (m && /error/i.test(m)) setAutoMsg(`ffmpeg: ${m.slice(0, 80)}`);
          });
          audioBuffer = extracted.audioBuffer;
        } catch (err) {
          const msg = err instanceof Error ? err.message : 'extract ล้มเหลว';
          setToast({ message: `ดึงเสียงจากวิดีโอล้มเหลว: ${msg}`, level: 'error' });
          return;
        }
      }
      if (!audioBuffer) {
        setToast({ message: 'ไฟล์นี้ไม่มี track เสียง', level: 'error' });
        return;
      }
      const cues = await generateCaptions(audioBuffer, { language: autoLang, modelSize: autoModel }, onProgress);
      if (cues.length === 0) {
        setToast({ message: 'ไม่พบเสียงพูดในไฟล์นี้', level: 'info' });
        return;
      }
      setSubtitles(cues);
      setToast({
        message: `สร้างคำบรรยายอัตโนมัติ ${cues.length} รายการ จาก ${target!.kind === 'video' ? 'เสียงในวิดีโอ' : 'ไฟล์เสียง'}`,
        level: 'success',
      });
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'Auto-caption ล้มเหลว';
      setToast({ message: `สร้างคำบรรยายล้มเหลว: ${msg}`, level: 'error' });
    } finally {
      setAutoBusy(false);
      setAutoPct(0);
      setAutoMsg('');
    }
  }

  async function importSrt(file: File) {
    try {
      const text = await file.text();
      const cues = parseSrt(text);
      if (cues.length === 0) {
        setToast({ message: 'ไม่พบคำบรรยายในไฟล์', level: 'error' });
        return;
      }
      setSubtitles(cues);
      setToast({ message: `นำเข้าคำบรรยาย ${cues.length} รายการ`, level: 'success' });
    } catch (err) {
      const msg = err instanceof Error ? err.message : 'นำเข้าไม่สำเร็จ';
      setToast({ message: `นำเข้า SRT ล้มเหลว: ${msg}`, level: 'error' });
    }
  }

  function exportSrt() {
    if (subtitles.length === 0) {
      setToast({ message: 'ยังไม่มีคำบรรยาย', level: 'info' });
      return;
    }
    const text = subtitles
      .map((c, i) => `${i + 1}\n${formatSrtTime(c.start)} --> ${formatSrtTime(c.end)}\n${c.text}\n`)
      .join('\n');
    const blob = new Blob([text], { type: 'text/plain;charset=utf-8' });
    const url = URL.createObjectURL(blob);
    const a = document.createElement('a');
    a.href = url;
    a.download = 'subtitles.srt';
    document.body.appendChild(a);
    a.click();
    a.remove();
    URL.revokeObjectURL(url);
  }

  return (
    <Section title="คำบรรยาย (SRT)" icon={<Subtitles size={14} />}>
      <div className="space-y-2">
        {/* Subtitle style controls */}
        <div className="rounded-md border border-capcut-border bg-capcut-surface/40 p-2 space-y-2">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-1.5 text-[11px] font-semibold text-capcut-text">
              <Palette size={12} className="text-capcut-orange" /> สไตล์คำบรรยาย
            </div>
            <button
              type="button"
              onClick={() => setSubtitleStyle(DEFAULT_SUBTITLE_STYLE)}
              className="text-[10px] text-capcut-muted hover:text-capcut-text flex items-center gap-1"
              data-tip="คืนค่าเริ่มต้น"
            >
              <RotateCcw size={10} /> รีเซ็ต
            </button>
          </div>

          {/* Position chips */}
          <div className="flex gap-1">
            {(['top', 'middle', 'bottom'] as SubtitlePosition[]).map((p) => (
              <button
                key={p}
                type="button"
                onClick={() => setSubtitleStyle({ position: p })}
                className={`flex-1 px-2 py-1 text-[10px] rounded border transition-colors ${
                  subtitleStyle.position === p
                    ? 'bg-capcut-blue/20 border-capcut-blue text-white'
                    : 'bg-capcut-surface border-capcut-border text-capcut-muted hover:text-capcut-text'
                }`}
              >
                {p === 'top' ? 'บน' : p === 'middle' ? 'กลาง' : 'ล่าง'}
              </button>
            ))}
          </div>

          {/* Font size + Bold */}
          <div className="grid grid-cols-2 gap-1.5">
            <div className="flex flex-col gap-0.5">
              <label className="text-[10px] text-capcut-muted">ขนาด ({subtitleStyle.fontSize}px)</label>
              <input
                type="range"
                min={14}
                max={64}
                step={1}
                value={subtitleStyle.fontSize}
                onChange={(e) => setSubtitleStyle({ fontSize: Number(e.target.value) })}
                className="h-2"
              />
            </div>
            <label className="flex items-center gap-1 text-[10px] text-capcut-muted mt-4">
              <input
                type="checkbox"
                checked={subtitleStyle.bold}
                onChange={(e) => setSubtitleStyle({ bold: e.target.checked })}
              />
              ตัวหนา
            </label>
          </div>

          {/* Colors */}
          <div className="grid grid-cols-3 gap-1.5">
            <ColorField
              label="ตัวอักษร"
              value={subtitleStyle.color}
              onChange={(v) => setSubtitleStyle({ color: v })}
            />
            <ColorField
              label="ขอบ"
              value={subtitleStyle.outlineColor}
              onChange={(v) => setSubtitleStyle({ outlineColor: v })}
            />
            <ColorField
              label="พื้นหลัง"
              value={subtitleStyle.background === 'none' ? '#00000000' : subtitleStyle.background}
              onChange={(v) => setSubtitleStyle({ background: v })}
              allowTransparent
            />
          </div>

          {/* Outline width */}
          <div className="flex items-center gap-2">
            <label className="text-[10px] text-capcut-muted shrink-0">ขอบหนา</label>
            <input
              type="range"
              min={0}
              max={6}
              step={1}
              value={subtitleStyle.outlineWidth}
              onChange={(e) => setSubtitleStyle({ outlineWidth: Number(e.target.value) })}
              className="flex-1 h-2"
            />
            <span className="text-[10px] font-mono w-4 text-right">{subtitleStyle.outlineWidth}</span>
          </div>

          {/* Live preview swatch */}
          <div className="rounded bg-capcut-black p-3 text-center" style={{ minHeight: 60 }}>
            <span
              style={{
                fontFamily: subtitleStyle.fontFamily,
                fontSize: Math.min(28, subtitleStyle.fontSize),
                color: subtitleStyle.color,
                fontWeight: subtitleStyle.bold ? 700 : 400,
                backgroundColor: subtitleStyle.background === 'none' ? 'transparent' : subtitleStyle.background,
                padding: subtitleStyle.background === 'none' ? 0 : '4px 12px',
                borderRadius: 4,
                WebkitTextStroke: subtitleStyle.outlineWidth > 0
                  ? `${subtitleStyle.outlineWidth}px ${subtitleStyle.outlineColor}`
                  : undefined,
                textShadow: subtitleStyle.outlineWidth > 0
                  ? undefined
                  : `0 0 ${Math.max(2, subtitleStyle.outlineWidth)}px ${subtitleStyle.outlineColor}`,
              }}
            >
              ตัวอย่างข้อความ
            </span>
          </div>
        </div>
        {/* Auto-Captions */}
        <div className="rounded-md border border-capcut-orange/30 bg-capcut-orange/5 p-2 space-y-2">
          <div className="flex items-center gap-1.5 text-[11px] font-semibold text-capcut-orange">
            <Sparkles size={12} /> สร้างคำบรรยายอัตโนมัติ (Whisper AI)
          </div>
          <div className="flex items-center gap-2">
            <Languages size={12} className="text-capcut-muted" />
            <select
              value={autoLang}
              onChange={(e) => setAutoLang(e.target.value as 'th' | 'en' | 'auto')}
              disabled={autoBusy}
              className="flex-1 h-7 bg-capcut-surface border border-capcut-border rounded px-1.5 text-xs disabled:opacity-50"
            >
              <option value="th">ภาษาไทย</option>
              <option value="en">English</option>
              <option value="auto">ตรวจจับอัตโนมัติ</option>
            </select>
          </div>
          <div className="flex items-center gap-2">
            <span className="text-capcut-muted text-[11px] w-3">⚙</span>
            <select
              value={autoModel}
              onChange={(e) => setAutoModel(e.target.value as WhisperModelSize)}
              disabled={autoBusy}
              className="flex-1 h-7 bg-capcut-surface border border-capcut-border rounded px-1.5 text-xs disabled:opacity-50"
              title="Whisper-tiny: เร็วแต่แม่นน้อย · base: ช้าลง 2× แต่แม่นกว่า"
            >
              <option value="tiny">Tiny (40MB, เร็ว)</option>
              <option value="base">Base (75MB, แม่นกว่า)</option>
            </select>
          </div>
          <button
            type="button"
            onClick={runAutoCaptions}
            disabled={autoBusy}
            className="w-full h-9 rounded-md bg-capcut-orange hover:bg-capcut-orange/90 text-white text-xs font-medium flex items-center justify-center gap-1.5 disabled:opacity-60"
          >
            {autoBusy ? (
              <>
                <Loader2 size={12} className="animate-spin" /> กำลังถอดเสียง...
              </>
            ) : (
              <>
                <Sparkles size={12} /> ถอดเสียงเป็นข้อความ
              </>
            )}
          </button>
          {autoBusy && (
            <div className="space-y-1">
              <div className="h-1 bg-capcut-surface rounded overflow-hidden">
                <div className="h-full bg-capcut-orange transition-all" style={{ width: `${autoPct}%` }} />
              </div>
              <div className="text-[10px] text-capcut-muted text-center">{autoMsg}</div>
            </div>
          )}
          <p className="text-[10px] text-capcut-muted leading-snug">
            ใช้ Whisper-tiny (รันในเบราว์เซอร์) · ดาวน์โหลด model ~40MB ครั้งแรก
            <br />
            <span className="inline-flex items-center gap-1">
              <FileVideo size={10} /> ถอดเสียงจากวิดีโอได้โดยตรง (ไม่ต้องมีไฟล์เสียงแยก)
            </span>
          </p>
        </div>

        <div className="flex gap-2">
          <button
            type="button"
            onClick={() => srtInputRef.current?.click()}
            className="flex-1 h-9 rounded-md bg-capcut-blue/20 hover:bg-capcut-blue/30 text-capcut-blue text-xs flex items-center justify-center gap-1"
          >
            <FileUp size={12} /> นำเข้า .srt
          </button>
          <button
            type="button"
            onClick={exportSrt}
            disabled={subtitles.length === 0}
            className="flex-1 h-9 rounded-md bg-capcut-surface hover:bg-capcut-border text-xs disabled:opacity-40"
          >
            ดาวน์โหลด
          </button>
          <input
            ref={srtInputRef}
            type="file"
            accept=".srt,text/plain"
            className="hidden"
            onChange={(e) => {
              const f = e.target.files?.[0];
              if (f) importSrt(f);
              e.target.value = '';
            }}
          />
        </div>
        <p className="text-[11px] text-capcut-muted">
          รองรับไฟล์ .srt มาตรฐาน — คำบรรยายจะแสดงบนตัวอย่างวิดีโอและมี marker บนไทม์ไลน์
        </p>
        {subtitles.length > 0 && (
          <div className="mt-2 max-h-40 overflow-y-auto border border-capcut-border rounded">
            {subtitles.slice(0, 50).map((c) => (
              <div
                key={c.id}
                className={`px-2 py-1 text-[11px] border-b border-capcut-border/40 last:border-b-0 ${
                  currentTime >= c.start && currentTime <= c.end ? 'bg-capcut-blue/10' : ''
                }`}
              >
                <div className="font-mono text-capcut-muted">
                  {formatTimeShort(c.start)} → {formatTimeShort(c.end)}
                </div>
                <div className="truncate">{c.text}</div>
              </div>
            ))}
            {subtitles.length > 50 && (
              <div className="px-2 py-1 text-[10px] text-capcut-muted text-center">
                … และอีก {subtitles.length - 50} รายการ
              </div>
            )}
          </div>
        )}
      </div>
    </Section>
  );
}

function ColorField({
  label,
  value,
  onChange,
  allowTransparent,
}: {
  label: string;
  value: string;
  onChange: (v: string) => void;
  allowTransparent?: boolean;
}) {
  // Convert hex/rgba to <input type="color"> compatible hex (alpha stripped).
  const hex = value.startsWith('#') ? value.slice(0, 7) : value;
  return (
    <div className="flex flex-col gap-0.5">
      <label className="text-[10px] text-capcut-muted">{label}</label>
      <div className="flex items-center gap-1">
        <input
          type="color"
          value={hex}
          onChange={(e) => onChange(e.target.value)}
          className="w-6 h-6 rounded cursor-pointer bg-transparent border border-capcut-border"
        />
        {allowTransparent && (
          <button
            type="button"
            onClick={() => onChange('none')}
            className="text-[9px] text-capcut-muted hover:text-capcut-text px-1 py-0.5 rounded border border-capcut-border"
            title="ไม่มีพื้นหลัง"
          >
            none
          </button>
        )}
      </div>
    </div>
  );
}