./kaisetsu-app/src/components/TimelineBlock.tsx

'use client';

import { useState, useRef, useEffect } from 'react';
import {
  MessageSquare,
  Mic,
  Pause,
  Clock,
  Volume2,
  Trash2,
  ChevronDown,
  ChevronUp,
  Plus,
  Loader2
} from 'lucide-react';

export const VOICE_TYPES = [
  { id: '7nO7lVCISGqz9Dhm3AAx', name: '男性1(落ち着いている、ニュース風)' },
  { id: 'hbgab64cBnhmszNvMx0a', name: '女性1(落ち着いている、ニュース風)' },
  { id: 'W4ihLGvcGWLGK4wB0Awj', name: '女性2(明るめ、スポーツニュース風)' },
  { id: 'P8wFRdNgC0J0v6Z08giL', name: '男性ナレーター1(超明るい、バラエティ風)' },
  { id: 'Rgib2k564qSdhNBylX7C', name: '男性ナレーター2(低い、重厚、ホラー風)' },
  { id: 'jhbUCjxMYhkEB9E3kSL0', name: '男性ナレーター3(落ち着いている、ドキュメンタリー風)' },
  { id: 'Nit9fPqVBSNo8FxQiLFE', name: '女性ナレーター1(優しい、ゆっくりめ、癒し系)' },
  { id: 'tzo3dQGeYH7eRPgDLKA4', name: '女性ナレーター2(高め、情報番組風)' },
] as const;

export type VoiceTypeId = typeof VOICE_TYPES[number]['id'];

export interface TimelineBlockData {
  id: string;
  type: 'dialogue' | 'narration' | 'silence';
  startTime: number;
  endTime?: number;
  speaker?: string;
  text?: string;
  voiceType?: VoiceTypeId;
  isPlaying?: boolean;
  timecode?: string;      // Absolute TC for display (e.g., "10;00;05;14")
  endTimecode?: string;   // Absolute end TC for display
  bgmLevel?: string;      // BGM level (High/Low)
  audioUrl?: string;      // Pre-synthesized audio URL
}

interface TimelineBlockProps {
  block: TimelineBlockData;
  isHighlighted?: boolean;
  tcOffsetSeconds?: number;
  onPlay?: (id: string, startTime: number) => void;
  onTextChange?: (id: string, text: string) => void;
  onVoiceTypeChange?: (id: string, voiceType: VoiceTypeId) => void;
  onSpeakerChange?: (id: string, speaker: string) => void;
  onDelete?: (id: string) => void;
  onTimestampClick?: (time: number, blockType: 'dialogue' | 'narration' | 'silence') => void;
  onAddNarration?: (afterTime: number) => void;
}

export default function TimelineBlock({
  block,
  isHighlighted,
  onPlay,
  onTextChange,
  onVoiceTypeChange,
  onSpeakerChange,
  onDelete,
  onTimestampClick,
  onAddNarration,
  tcOffsetSeconds = 35985
}: TimelineBlockProps) {
  const [isExpanded, setIsExpanded] = useState(true);
  const [isPlayingAudio, setIsPlayingAudio] = useState(false);
  const [isLoadingAudio, setIsLoadingAudio] = useState(false);
  const [audioPlaybackRate, setAudioPlaybackRate] = useState(1);
  const textareaRef = useRef<HTMLTextAreaElement>(null);
  const audioRef = useRef<HTMLAudioElement | null>(null);

  // Convert relative seconds to absolute TC string using offset
  const secondsToTC = (seconds: number): string => {
    const abs = seconds + tcOffsetSeconds;
    const hrs = Math.floor(abs / 3600);
    const mins = Math.floor((abs % 3600) / 60);
    const secs = Math.floor(abs % 60);
    const frames = Math.floor((abs % 1) * 30);
    return `${hrs.toString().padStart(2, '0')};${mins.toString().padStart(2, '0')};${secs.toString().padStart(2, '0')};${frames.toString().padStart(2, '0')}`;
  };

  const getTimecodeDisplay = (): string => {
    const startTC = secondsToTC(block.startTime);
    if (block.endTime !== undefined) {
      return `${startTC} - ${secondsToTC(block.endTime)}`;
    }
    return startTC;
  };

  const getDuration = (): number => {
    if (block.endTime !== undefined) {
      return block.endTime - block.startTime;
    }
    return 0;
  };

  const handleTimestampClick = () => {
    onTimestampClick?.(block.startTime, block.type);
  };

  const handlePlayPreview = async () => {
    // If already playing, stop
    if (isPlayingAudio && audioRef.current) {
      audioRef.current.pause();
      audioRef.current.currentTime = 0;
      setIsPlayingAudio(false);
      return;
    }

    if (!block.text) return;

    // Use pre-synthesized audio if available
    if (block.audioUrl) {
      if (audioRef.current) {
        audioRef.current.pause();
      }

      const audio = new Audio(block.audioUrl);
      audio.playbackRate = audioPlaybackRate;
      audioRef.current = audio;

      audio.onended = () => {
        setIsPlayingAudio(false);
      };

      audio.onerror = () => {
        setIsPlayingAudio(false);
        console.error('Audio playback error');
      };

      setIsPlayingAudio(true);
      await audio.play();
      return;
    }

    // Otherwise, generate audio on-demand
    setIsLoadingAudio(true);
    try {
      // Get dictionary from localStorage
      const savedDict = localStorage.getItem('kaisetsu-user-dictionary');
      const dictionary = savedDict ? JSON.parse(savedDict) : [];

      const response = await fetch('/api/tts', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          text: block.text,
          voiceType: block.voiceType || '7nO7lVCISGqz9Dhm3AAx',
          dictionary,
        }),
      });

      if (!response.ok) {
        const errorData = await response.json();
        throw new Error(errorData.error || 'TTS failed');
      }

      const audioBlob = await response.blob();
      const audioUrl = URL.createObjectURL(audioBlob);

      // Create and play audio
      if (audioRef.current) {
        audioRef.current.pause();
        URL.revokeObjectURL(audioRef.current.src);
      }

      const audio = new Audio(audioUrl);
      audio.playbackRate = audioPlaybackRate;
      audioRef.current = audio;

      audio.onended = () => {
        setIsPlayingAudio(false);
        URL.revokeObjectURL(audioUrl);
      };

      audio.onerror = () => {
        setIsPlayingAudio(false);
        URL.revokeObjectURL(audioUrl);
        console.error('Audio playback error');
      };

      setIsPlayingAudio(true);
      await audio.play();
    } catch (error) {
      console.error('TTS error:', error);
      setIsPlayingAudio(false);
    } finally {
      setIsLoadingAudio(false);
    }
  };

  const handleAddNarration = () => {
    const afterTime = block.endTime || block.startTime;
    onAddNarration?.(afterTime);
  };

  // Silence block
  if (block.type === 'silence') {
    return (
      <div className="relative pl-8 pb-4">
        <div className="absolute left-3 top-0 bottom-0 w-0.5 bg-gray-200" />
        <div className="absolute left-1.5 top-2 w-4 h-4 rounded-full bg-gray-300 border-2 border-white" />

        <div className="bg-gray-50 border border-dashed border-gray-300 rounded-lg p-3 ml-4">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-2 text-gray-500 text-sm">
              <Clock className="w-4 h-4" />
              <span>セリフなし(無音)</span>
              <span className="font-mono bg-gray-200 px-2 py-0.5 rounded text-gray-700">
                {getDuration().toFixed(1)}秒
              </span>
            </div>
            <button
              onClick={handleAddNarration}
              className="flex items-center gap-1 px-2 py-1 text-xs text-gray-600 hover:bg-gray-200 rounded transition-colors"
              title="この後に解説音声を追加"
            >
              <Plus className="w-3 h-3" />
              追加
            </button>
          </div>
        </div>
      </div>
    );
  }

  // Dialogue block
  if (block.type === 'dialogue') {
    return (
      <div className={`relative pl-8 pb-4 transition-all ${isHighlighted ? 'scale-[1.01]' : ''}`}>
        <div className="absolute left-3 top-0 bottom-0 w-0.5 bg-gray-200" />
        <div className={`absolute left-1.5 top-2 w-4 h-4 rounded-full border-2 border-white ${
          isHighlighted ? 'bg-gray-900 animate-pulse' : 'bg-gray-600'
        }`} />

        <div className={`ml-4 rounded-xl overflow-hidden border transition-all ${
          isHighlighted
            ? 'border-gray-400 bg-gray-50 shadow-md'
            : 'border-gray-200 bg-white'
        }`}>
          <div className="flex items-center justify-between px-4 py-2 bg-gray-50 border-b border-gray-200">
            <div className="flex items-center gap-3">
              <button
                onClick={handleTimestampClick}
                className="flex items-center gap-1 font-mono text-xs bg-gray-200 text-gray-700 px-2 py-1 rounded hover:bg-gray-300 transition-colors"
              >
                <Clock className="w-3 h-3" />
                {getTimecodeDisplay()}
              </button>
              <div className="flex items-center gap-1.5">
                <MessageSquare className="w-4 h-4 text-gray-600" />
                <input
                  type="text"
                  value={block.speaker || ''}
                  onChange={(e) => onSpeakerChange?.(block.id, e.target.value)}
                  placeholder="話者"
                  className="text-sm font-medium text-gray-700 bg-transparent border-b border-transparent hover:border-gray-300 focus:border-gray-500 focus:outline-none px-1 py-0 w-24"
                />
              </div>
              {isHighlighted && (
                <span className="text-xs bg-gray-900 text-white px-2 py-0.5 rounded-full">
                  再生中
                </span>
              )}
            </div>
            <div className="flex items-center gap-1">
              <button
                onClick={handleAddNarration}
                className="flex items-center gap-1 px-2 py-1 text-xs text-gray-600 hover:bg-gray-200 rounded transition-colors"
                title="この後に解説音声を追加"
              >
                <Plus className="w-3 h-3" />
                追加
              </button>
              <button
                onClick={() => setIsExpanded(!isExpanded)}
                className="p-1 hover:bg-gray-200 rounded transition-colors"
              >
                {isExpanded ? (
                  <ChevronUp className="w-4 h-4 text-gray-500" />
                ) : (
                  <ChevronDown className="w-4 h-4 text-gray-500" />
                )}
              </button>
            </div>
          </div>

          {isExpanded && (
            <div className="p-4">
              <p className="text-gray-700 leading-relaxed">
                {block.text}
              </p>
            </div>
          )}
        </div>
      </div>
    );
  }

  // Narration block
  return (
    <div className={`relative pl-8 pb-4 transition-all ${isHighlighted ? 'scale-[1.01]' : ''}`}>
      <div className="absolute left-3 top-0 bottom-0 w-0.5 bg-purple-200" />
      <div className={`absolute left-1.5 top-2 w-4 h-4 rounded-full border-2 border-white ${
        isHighlighted ? 'bg-purple-600 animate-pulse' : 'bg-purple-500'
      }`} />

      <div className={`ml-4 rounded-xl overflow-hidden border-2 transition-all ${
        isHighlighted
          ? 'border-purple-400 bg-purple-50 shadow-md'
          : 'border-purple-300 bg-purple-50'
      }`}>
        <div className="flex items-center justify-between px-4 py-2 bg-purple-100 border-b border-purple-200">
          <div className="flex items-center gap-3">
            <button
              onClick={handleTimestampClick}
              className="flex items-center gap-1 font-mono text-xs bg-purple-200 text-purple-700 px-2 py-1 rounded hover:bg-purple-300 transition-colors"
            >
              <Clock className="w-3 h-3" />
              {getTimecodeDisplay()}
            </button>
            <div className="flex items-center gap-1.5">
              <Mic className="w-4 h-4 text-purple-600" />
              <input
                type="text"
                value={block.speaker || '解説音声'}
                onChange={(e) => onSpeakerChange?.(block.id, e.target.value)}
                className="text-sm font-medium text-purple-700 bg-transparent border-b border-transparent hover:border-purple-300 focus:border-purple-500 focus:outline-none px-1 py-0 w-28"
              />
            </div>
            {/* Voice type selector */}
            <select
              value={block.voiceType || '7nO7lVCISGqz9Dhm3AAx'}
              onChange={(e) => onVoiceTypeChange?.(block.id, e.target.value as VoiceTypeId)}
              className="text-xs bg-white border border-gray-300 rounded px-2 py-1 text-gray-700 focus:outline-none focus:ring-1 focus:ring-gray-400"
            >
              {VOICE_TYPES.map((voice) => (
                <option key={voice.id} value={voice.id}>
                  {voice.name}
                </option>
              ))}
            </select>
          </div>
          <div className="flex items-center gap-1">
            <button
              onClick={() => onDelete?.(block.id)}
              className="p-1.5 hover:bg-red-100 rounded transition-colors text-red-500"
              title="削除"
            >
              <Trash2 className="w-4 h-4" />
            </button>
            <button
              onClick={handleAddNarration}
              className="flex items-center gap-1 px-2 py-1 text-xs text-purple-600 hover:bg-purple-200 rounded transition-colors"
              title="この後に解説音声を追加"
            >
              <Plus className="w-3 h-3" />
              追加
            </button>
            <button
              onClick={() => setIsExpanded(!isExpanded)}
              className="p-1 hover:bg-purple-200 rounded transition-colors"
            >
              {isExpanded ? (
                <ChevronUp className="w-4 h-4 text-purple-500" />
              ) : (
                <ChevronDown className="w-4 h-4 text-purple-500" />
              )}
            </button>
          </div>
        </div>

        {isExpanded && (
          <div className="p-4 bg-white space-y-3">
            <textarea
              ref={textareaRef}
              value={block.text || ''}
              onChange={(e) => onTextChange?.(block.id, e.target.value)}
              className="w-full min-h-[80px] p-3 bg-white border border-purple-200 rounded-lg text-gray-700 focus:outline-none focus:ring-2 focus:ring-purple-400 resize-none text-sm leading-relaxed"
              placeholder="解説音声テキストを入力..."
            />
            <div className="flex items-center gap-3">
              <button
                onClick={handlePlayPreview}
                disabled={isLoadingAudio}
                className={`flex items-center gap-2 px-4 py-2 rounded-lg text-sm font-medium transition-all ${
                  isLoadingAudio
                    ? 'bg-purple-200 text-purple-500 cursor-wait'
                    : isPlayingAudio
                      ? 'bg-red-100 text-red-600'
                      : 'bg-purple-100 text-purple-700 hover:bg-purple-200'
                }`}
              >