import React, { useEffect, useMemo, useRef, useState } from 'react';

import { computeTimeSec } from '../../main/video/videoPlaybackStore';
import type { SessionState } from '../../shared/ipc/contracts';
import type { SceneViewCamera } from '../../shared/types';
import { useEditorI18n } from '../editor/i18n/EditorI18nContext';
import { ContainedVideo } from '../shared/ContainedVideo';
import { RotatedImage } from '../shared/RotatedImage';
import { useAssetUrl } from '../shared/useAssetImageUrl';
import { useVideoPlaybackState } from '../shared/video/useVideoPlaybackState';

import styles from './ControlScenePreview.module.css';

type Props = {
  session: SessionState | null;
  videoRef: React.RefObject<HTMLVideoElement | null>;
  viewCamera?: SceneViewCamera | null;
  onContentRectChange?: (rect: { x: number; y: number; w: number; h: number }) => void;
};

function fmt(sec: number): string {
  if (!Number.isFinite(sec) || sec < 0) return '0:00';
  const s = Math.floor(sec);
  const m = Math.floor(s / 60);
  const r = s % 60;
  return `${String(m)}:${String(r).padStart(2, '0')}`;
}

export function ControlScenePreview({ session, videoRef, viewCamera = null, onContentRectChange }: Props) {
  const { t } = useEditorI18n();
  const [vp, video] = useVideoPlaybackState();
  const scene =
    session?.project && session.currentSceneId ? session.project.scenes[session.currentSceneId] : undefined;
  const url = useAssetUrl(scene?.previewAssetId ?? null);
  const rot = scene?.previewRotationDeg ?? 0;
  const isVideo = scene?.previewAssetType === 'video';
  const assetId = scene?.previewAssetType === 'video' ? scene.previewAssetId : null;
  const autostart = scene?.previewVideoAutostart ?? false;
  const lastTargetRef = useRef<{ sceneKey: string; assetId: string; autostart: boolean } | null>(null);

  const [tick, setTick] = useState(0);
  const dur = useMemo(
    () => {
      const v = videoRef.current;
      if (!v) return 0;
      return Number.isFinite(v.duration) ? v.duration : 0;
    },
    // tick: timeupdate / loadedmetadata перечитывают duration и currentTime
    // eslint-disable-next-line react-hooks/exhaustive-deps -- намеренно
    [tick, videoRef],
  );
  const cur = useMemo(
    () => {
      const v = videoRef.current;
      if (!v) return 0;
      return Number.isFinite(v.currentTime) ? v.currentTime : 0;
    },
    // eslint-disable-next-line react-hooks/exhaustive-deps -- намеренно
    [tick, videoRef],
  );
  const pct = dur > 0 ? Math.max(0, Math.min(1, cur / dur)) : 0;

  useEffect(() => {
    if (!isVideo) return;
    if (!assetId) return;
    const sceneKey = session?.project?.currentGraphNodeId ?? session?.currentSceneId ?? '';
    const prev = lastTargetRef.current;
    if (prev && prev.sceneKey === sceneKey && prev.assetId === assetId && prev.autostart === autostart) {
      return;
    }
    lastTargetRef.current = { sceneKey, assetId, autostart };
    void video.dispatch({
      kind: 'target.set',
      assetId,
      autostart,
    });
  }, [assetId, isVideo, autostart, session?.currentSceneId, session?.project?.currentGraphNodeId, video]);

  useEffect(() => {
    const v = videoRef.current;
    if (!v) return;
    if (!vp) return;
    if (vp.targetAssetId !== assetId) return;
    v.playbackRate = vp.playbackRate;
    const desired = computeTimeSec(vp, vp.serverNowMs);
    if (Number.isFinite(desired) && Math.abs(v.currentTime - desired) > 0.25) {
      v.currentTime = Math.max(0, desired);
    }
    if (vp.playing) {
      void v.play().catch(() => undefined);
    } else {
      v.pause();
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps -- avoid reruns on 500ms heartbeats (serverNowMs-only updates)
  }, [assetId, url, vp?.revision, vp?.targetAssetId, vp?.playing, vp?.playbackRate, videoRef]);

  const scrubClass = [styles.scrub, dur ? styles.scrubPointer : styles.scrubDefault].join(' ');

  return (
    <div className={styles.root}>
      {url && scene?.previewAssetType === 'image' ? (
        <RotatedImage
          url={url}
          rotationDeg={rot}
          mode="contain"
          viewCamera={viewCamera}
          onContentRectChange={onContentRectChange}
        />
      ) : url && isVideo ? (
        <ContainedVideo
          url={url}
          rotationDeg={rot}
          videoRef={videoRef}
          playsInline
          loop={Boolean(scene?.settings?.loopVideo)}
          preload="auto"
          viewCamera={viewCamera}
          onContentRectChange={onContentRectChange}
          onTimeUpdate={() => setTick((x) => x + 1)}
          onLoadedMetadata={() => setTick((x) => x + 1)}
        >
          <track kind="captions" srcLang="ru" label={t('control.previewTrackLabel')} />
        </ContainedVideo>
      ) : (
        <div className={styles.placeholder} />
      )}

      {isVideo ? (
        <div className={styles.controls}>
          <div
            role="slider"
            tabIndex={0}
            aria-valuemin={0}
            aria-valuemax={dur > 0 ? Math.round(dur) : 0}
            aria-valuenow={Math.round(cur)}
            className={scrubClass}
            onClick={(e) => {
              const v = videoRef.current;
              if (!v || !dur) return;
              const rect = (e.currentTarget as HTMLDivElement).getBoundingClientRect();
              const next = (e.clientX - rect.left) / rect.width;
              void video.dispatch({ kind: 'seek', timeSec: Math.max(0, Math.min(dur, next * dur)) });
              setTick((x) => x + 1);
            }}
            onKeyDown={(e) => {
              if (!dur) return;
              if (e.key === 'ArrowLeft') void video.dispatch({ kind: 'seek', timeSec: Math.max(0, cur - 5) });
              if (e.key === 'ArrowRight')
                void video.dispatch({ kind: 'seek', timeSec: Math.min(dur, cur + 5) });
              if (e.key === 'ArrowLeft' || e.key === 'ArrowRight') setTick((x) => x + 1);
            }}
            title={t('control.scrubSeek')}
          >
            <div className={styles.scrubFill} style={{ width: `${String(Math.round(pct * 100))}%` }} />
          </div>
          <div className={styles.row}>
            <div className={styles.transport}>
              <button
                type="button"
                className={styles.transportBtn}
                onClick={() => void video.dispatch({ kind: 'play' })}
                title={t('control.transportPlay')}
              >
                ▶
              </button>
              <button
                type="button"
                className={styles.transportBtn}
                onClick={() => void video.dispatch({ kind: 'pause' })}
                title={t('control.transportPause')}
              >
                ❚❚
              </button>
              <button
                type="button"
                className={styles.transportBtn}
                onClick={() => {
                  void video.dispatch({ kind: 'stop' });
                  setTick((x) => x + 1);
                }}
                title={t('control.transportStop')}
              >
                ■
              </button>
            </div>
            <div>
              {fmt(cur)} / {dur ? fmt(dur) : '—:—'}
            </div>
          </div>
        </div>
      ) : null}
    </div>
  );
}
