import React from 'react';
import {
  useCurrentFrame,
  interpolate,
  spring,
  useVideoConfig,
} from 'remotion';
import type { TelopSegment } from './telopTypes';
import { TELOP_CONFIG } from '../videoConfig';
import {
  template1_gradient,
  template2_purpleStroke,
  template3_gradientText,
  template4_negative,
  template4_negative_v2,
  template6_whiteGradientText,
  animation_none,
  animation_slideIn,
  animation_fadeOnly,
  animation_slideFromLeft,
  animation_fadeBlurFromBottom,
  animation_slideLeftFadeBlur,
  animation_fadeFromRight,
  animation_fadeFromLeft,
  animation_charByChar,
} from './telopStyles';

interface TelopProps {
  segment: TelopSegment;
}

// ネガティブテンプレートをIDに基づいてランダム選択
const getNegativeTemplate = (id: number) => {
  return id % 2 === 0 ? template4_negative : template4_negative_v2;
};

// 強調テンプレートをIDに基づいてランダム選択（T1 or T6）
const getEmphasisTemplate = (id: number) => {
  return id % 2 === 0 ? template1_gradient : template6_whiteGradientText;
};

// styleからテンプレートを選択
const getTemplateConfig = (segment: TelopSegment) => {
  // 明示的にtemplateが指定されている場合
  if (segment.template === 1) return template1_gradient;
  if (segment.template === 2) return template2_purpleStroke;
  if (segment.template === 3) return template3_gradientText;
  if (segment.template === 4) return template4_negative;
  if (segment.template === 5) return template4_negative_v2;
  if (segment.template === 6) return template6_whiteGradientText;

  // styleから自動マッピング
  switch (segment.style) {
    case 'success':
      return template3_gradientText; // ポイント
    case 'warning':
      return getNegativeTemplate(segment.id); // ネガティブ（ランダム）
    case 'emphasis':
      return getEmphasisTemplate(segment.id); // 強調（T1/T6ランダム）
    default:
      return template2_purpleStroke; // 基本
  }
};

// IDベースでアニメーションをばらけさせる（fadeOnly用）
// 右からのアニメーションは除外
const getVariedAnimation = (id: number) => {
  const animations = [
    animation_fadeOnly,           // 0: フェードのみ
    animation_fadeFromLeft,       // 1: 左からフェードイン
    animation_fadeOnly,           // 2: フェードのみ
    animation_slideFromLeft,      // 3: 左からスライドイン
    animation_fadeOnly,           // 4: フェードのみ
    animation_slideLeftFadeBlur,  // 5: 左スライド+フェード+ブラー
  ];
  return animations[id % animations.length];
};

// アニメーションテンプレートを選択
// デフォルトはアニメーションなし。後から変更可能
const getAnimationConfig = (segment: TelopSegment) => {
  // 明示的にslideInが指定されている場合（warning/emphasisなど）
  if (segment.animation === 'slideIn') return animation_slideIn;

  // fadeOnlyはIDベースでバリエーションを付ける
  if (segment.animation === 'fadeOnly') return getVariedAnimation(segment.id);

  // その他の明示的な指定
  if (segment.animation === 'slideFromLeft') return animation_slideFromLeft;
  if (segment.animation === 'fadeBlurFromBottom') return animation_fadeBlurFromBottom;
  if (segment.animation === 'slideLeftFadeBlur') return animation_slideLeftFadeBlur;
  if (segment.animation === 'fadeFromRight') return animation_fadeFromRight;
  if (segment.animation === 'fadeFromLeft') return animation_fadeFromLeft;
  if (segment.animation === 'charByChar') return animation_charByChar;
  if (segment.animation === 'none') return animation_none;

  // デフォルト: 左スライド+フェード+ブラー
  return animation_slideLeftFadeBlur;
};

// HEXカラーをRGBに変換
const hexToRgb = (hex: string) => {
  const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
  return result ? {
    r: parseInt(result[1], 16),
    g: parseInt(result[2], 16),
    b: parseInt(result[3], 16),
  } : { r: 0, g: 0, b: 0 };
};

// 2色間を補間
const interpolateColor = (color1: string, color2: string, t: number) => {
  const c1 = hexToRgb(color1);
  const c2 = hexToRgb(color2);
  const r = Math.round(c1.r + (c2.r - c1.r) * t);
  const g = Math.round(c1.g + (c2.g - c1.g) * t);
  const b = Math.round(c1.b + (c2.b - c1.b) * t);
  return `rgb(${r}, ${g}, ${b})`;
};

// 一文字ずつアニメーションするコンポーネント
const CharByCharText: React.FC<{
  text: string;
  localFrame: number;
  fps: number;
  config: any;
  animation: any;
  duration: number;
}> = ({ text, localFrame, fps, config, animation, duration }) => {
  const { font, textShadow } = config;
  const charDelay = (animation as any).charDelay || 2;
  const chars = text.split('');
  const fillGradient = (font as any).fillGradient;
  const hasFillGradient = fillGradient?.enabled;

  // ★出口はアニメーション無し（フェードアウトしない）。入口は文字ごとのcharOpacityで表現。
  const overallOpacity = 1;

  return (
    <span style={{ display: 'inline-flex', opacity: overallOpacity }}>
      {chars.map((char, index) => {
        const charFrame = localFrame - index * charDelay;

        const charSpring = spring({
          frame: Math.max(0, charFrame),
          fps,
          config: animation.spring,
        });

        const translateY = interpolate(
          charSpring,
          [0, 1],
          [-animation.slideInDistance, 0]
        );

        const charOpacity = interpolate(
          charFrame,
          [0, 4],
          [0, 1],
          { extrapolateLeft: 'clamp', extrapolateRight: 'clamp' }
        );

        // グラデーションの場合は文字位置に応じた色を計算
        let charColor = font.color;
        if (hasFillGradient) {
          const t = chars.length > 1 ? index / (chars.length - 1) : 0;
          charColor = interpolateColor(fillGradient.start, fillGradient.end, t);
        }

        return (
          <span
            key={index}
            style={{
              display: 'inline-block',
              transform: `translateY(${translateY}px)`,
              opacity: charOpacity,
              fontSize: font.size,
              fontWeight: font.weight,
              fontFamily: font.family,
              fontStyle: font.style,
              textShadow: `${textShadow.offsetX}px ${textShadow.offsetY}px ${textShadow.blur}px ${textShadow.color}`,
              color: charColor,
            }}
          >
            {char === ' ' ? '\u00A0' : char}
          </span>
        );
      })}
    </span>
  );
};

export const Telop: React.FC<TelopProps> = ({ segment }) => {
  const frame = useCurrentFrame();
  const { fps, width } = useVideoConfig();

  // テンプレートを取得し、フォーマット別設定で上書き
  const baseConfig = getTemplateConfig(segment);
  const animation = getAnimationConfig(segment);
  const config = {
    ...baseConfig,
    font: { ...baseConfig.font, size: TELOP_CONFIG.fontSize },
    position: {
      ...baseConfig.position,
      bottom: TELOP_CONFIG.bottomOffset,
      maxWidth: TELOP_CONFIG.maxWidth,
      containerPadding: TELOP_CONFIG.containerPadding,
    },
  };
  const { font, background, position, textStroke, textShadow } = config;

  const localFrame = frame - segment.startFrame;
  const duration = segment.endFrame - segment.startFrame;

  // アニメーションなしの場合は常に不透明度1
  const hasAnimation = animation.fadeInDuration > 0 || animation.fadeOutDuration > 0;

  // durationが短い場合はフェード時間を調整
  const fadeIn = Math.min(animation.fadeInDuration, duration / 3);

  // ★入口だけアニメーション、出口はアニメーション無し（ハードカット）
  //   フェードインのみ適用し、表示後は opacity=1 を維持（extrapolateRight: clamp）。
  //   出口でフェードアウトすると「消える瞬間に早く薄くなる」ため、持続表示モードでは
  //   次のテロップへ即バトンタッチ（パッと切替）する方が音声と一致して見える。
  const opacity = hasAnimation
    ? interpolate(
        localFrame,
        [0, Math.max(1, fadeIn)],
        [0, 1],
        {
          extrapolateLeft: 'clamp',
          extrapolateRight: 'clamp',
        }
      )
    : 1;

  const slideIn = animation.slideInDistance > 0
    ? spring({
        frame: localFrame,
        fps,
        config: animation.spring,
      })
    : 1;

  // スライド方向に応じてtransformを計算
  const slideDirection = (animation as any).slideDirection || 'up';
  let translateX = 0;
  let translateY = 0;

  if (animation.slideInDistance > 0) {
    const slideValue = interpolate(slideIn, [0, 1], [animation.slideInDistance, 0]);
    switch (slideDirection) {
      case 'left':
        translateX = -slideValue;
        break;
      case 'right':
        translateX = slideValue;
        break;
      case 'up':
        translateY = slideValue;
        break;
      case 'down':
        translateY = -slideValue;
        break;
    }
  }

  // テキストを改行で分割
  const textLines = segment.text.split('\n');

  // charByCharアニメーションの場合は特別処理
  const isCharByChar = segment.animation === 'charByChar';

  if (isCharByChar && background.enabled) {
    return (
      <div
        style={{
          position: 'absolute',
          bottom: position.bottom,
          left: 0,
          right: 0,
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          padding: position.containerPadding,
          zIndex: 200,
        }}
      >
        <div
          style={{
            background: background.gradient,
            padding: background.padding,
            borderRadius: background.borderRadius,
            maxWidth: position.maxWidth,
            backdropFilter: background.backdropFilter,
            boxShadow: background.boxShadow,
            border: background.border,
          }}
        >
          <div style={{ margin: 0, textAlign: 'center', lineHeight: font.lineHeight }}>
            <CharByCharText
              text={segment.text}
              localFrame={localFrame}
              fps={fps}
              config={config}
              animation={animation}
              duration={duration}
            />
          </div>
        </div>
      </div>
    );
  }

  // テンプレート1（背景あり）の場合はCSSベース
  if (background.enabled) {
    const fillGradient = (font as any).fillGradient;
    const hasFillGradient = fillGradient?.enabled;

    // グラデーションテキスト用のスタイル
    const textStyle: React.CSSProperties = {
      fontSize: font.size,
      fontWeight: font.weight,
      fontFamily: font.family,
      fontStyle: font.style,
      margin: 0,
      textAlign: 'center',
      lineHeight: font.lineHeight,
      letterSpacing: font.letterSpacing,
      textShadow: `${textShadow.offsetX}px ${textShadow.offsetY}px ${textShadow.blur}px ${textShadow.color}`,
      whiteSpace: 'pre-line',
    };

    // fillGradientが有効な場合はCSSグラデーションテキストを適用
    if (hasFillGradient) {
      Object.assign(textStyle, {
        background: `linear-gradient(90deg, ${fillGradient.start} 0%, ${fillGradient.end} 100%)`,
        WebkitBackgroundClip: 'text',
        WebkitTextFillColor: 'transparent',
        backgroundClip: 'text',
      });
    } else {
      textStyle.color = font.color;
    }

    return (
      <div
        style={{
          position: 'absolute',
          bottom: position.bottom,
          left: 0,
          right: 0,
          display: 'flex',
          justifyContent: 'center',
          alignItems: 'center',
          padding: position.containerPadding,
          opacity,
          transform: `translate(${translateX}px, ${translateY}px)`,
          zIndex: 200, // サムネイルより前面に
        }}
      >
        <div
          style={{
            background: background.gradient,
            padding: background.padding,
            borderRadius: background.borderRadius,
            maxWidth: position.maxWidth,
            backdropFilter: background.backdropFilter,
            boxShadow: background.boxShadow,
            border: background.border,
          }}
        >
          <p style={textStyle}>
            {segment.text}
          </p>
        </div>
      </div>
    );
  }

  // テンプレート2, 3（背景なし、SVGベース）
  const strokeGradientId = `stroke-gradient-${segment.id}`;
  const fillGradientId = `fill-gradient-${segment.id}`;
  const filterId = `shadow-filter-${segment.id}`;

  const svgWidth = width;
  const lineHeight = font.size * 1.3; // 行間（複数行のdy間隔用）
  // ★縦位置統一: 背景ありテロップ(<p>: 高さ = font.size * font.lineHeight)と
  //   完全に同じ高さの箱にフィットさせる。旧 font.size*2(160px) だと
  //   背景なしテロップだけ約32px上にズレていた。overflow:visibleでストローク/影は箱外も描画される。
  const boxLineHeight = font.size * font.lineHeight;
  const svgHeight = boxLineHeight + (textLines.length - 1) * lineHeight;
  const baseY = svgHeight / 2 - ((textLines.length - 1) * lineHeight) / 2 + font.size * 0.37;

  const strokeGradient = (textStroke as any).gradient || { start: '#ffffff', end: '#ffffff' };
  const fillGradient = (font as any).fillGradient;
  const hasFillGradient = fillGradient?.enabled;
  const textOpacity = (font as any).opacity ?? 1;

  return (
    <div
      style={{
        position: 'absolute',
        bottom: position.bottom,
        left: 0,
        right: 0,
        display: 'flex',
        justifyContent: 'center',
        alignItems: 'center',
        padding: position.containerPadding,
        opacity,
        transform: `translate(${translateX}px, ${translateY}px)`,
        zIndex: 200, // サムネイルより前面に
      }}
    >
      <svg
        width={svgWidth}
        height={svgHeight}
        style={{
          overflow: 'visible',
          display: 'block',
          opacity: textOpacity,
        }}
      >
        <defs>
          <linearGradient id={strokeGradientId} x1="0%" y1="0%" x2="100%" y2="0%">
            <stop offset="0%" stopColor={strokeGradient.start} />
            <stop offset="100%" stopColor={strokeGradient.end} />
          </linearGradient>

          {hasFillGradient && (
            <linearGradient id={fillGradientId} x1="0%" y1="0%" x2="100%" y2="0%">
              <stop offset="0%" stopColor={fillGradient.start} />
              <stop offset="100%" stopColor={fillGradient.end} />
            </linearGradient>
          )}

          <filter id={filterId} x="-50%" y="-50%" width="200%" height="200%">
            <feDropShadow
              dx={textShadow.offsetX}
              dy={textShadow.offsetY}
              stdDeviation={textShadow.blur / 2}
              floodColor="black"
              floodOpacity="0.85"
            />
          </filter>
        </defs>

        {/* ストローク */}
        <text
          x="50%"
          y={baseY}
          textAnchor="middle"
          style={{
            fontSize: font.size,
            fontWeight: font.weight,
            fontFamily: font.family,
            fontStyle: font.style,
            letterSpacing: font.letterSpacing,
          }}
          fill="none"
          stroke={`url(#${strokeGradientId})`}
          strokeWidth={textStroke.width}
          strokeLinejoin="round"
          strokeLinecap="round"
          filter={`url(#${filterId})`}
        >
          {textLines.map((line, index) => (
            <tspan key={index} x="50%" dy={index === 0 ? 0 : lineHeight}>
              {line}
            </tspan>
          ))}
        </text>

        {/* 塗り */}
        <text
          x="50%"
          y={baseY}
          textAnchor="middle"
          style={{
            fontSize: font.size,
            fontWeight: font.weight,
            fontFamily: font.family,
            fontStyle: font.style,
            letterSpacing: font.letterSpacing,
          }}
          fill={hasFillGradient ? `url(#${fillGradientId})` : font.color}
        >
          {textLines.map((line, index) => (
            <tspan key={index} x="50%" dy={index === 0 ? 0 : lineHeight}>
              {line}
            </tspan>
          ))}
        </text>
      </svg>
    </div>
  );
};
