import { useEffect, useRef, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { useAuth } from '../context/AuthContext';
import { useWatchSession } from '../hooks/useWatchSession';
import { XIcon } from './icons';

interface YTPlayer {
  playVideo: () => void;
  pauseVideo: () => void;
  seekTo: (seconds: number, allowSeekAhead: boolean) => void;
  getCurrentTime: () => number;
  getPlayerState: () => number;
  destroy: () => void;
}

interface YTPlayerOptions {
  width: string | number;
  height: string | number;
  videoId: string;
  playerVars?: { autoplay?: 0 | 1; controls?: 0 | 1; modestbranding?: 0 | 1 };
  events?: {
    onReady?: (ev: { target: YTPlayer }) => void;
    onStateChange?: (ev: { data: number; target: YTPlayer }) => void;
  };
}

interface YTNamespace {
  Player: new (elementId: string | HTMLElement, opts: YTPlayerOptions) => YTPlayer;
  PlayerState: { UNSTARTED: -1; ENDED: 0; PLAYING: 1; PAUSED: 2; BUFFERING: 3; CUED: 5 };
}

declare global {
  interface Window {
    YT?: YTNamespace;
    onYouTubeIframeAPIReady?: () => void;
  }
}

const IFRAME_API_URL = 'https://www.youtube.com/iframe_api';
let apiPromise: Promise<YTNamespace> | null = null;

function loadIframeApi(): Promise<YTNamespace> {
  if (apiPromise) return apiPromise;
  apiPromise = new Promise((resolve, reject) => {
    if (typeof window === 'undefined') {
      reject(new Error('no window'));
      return;
    }
    if (window.YT?.Player) {
      resolve(window.YT);
      return;
    }
    const prev = window.onYouTubeIframeAPIReady;
    window.onYouTubeIframeAPIReady = () => {
      try {
        prev?.();
      } catch {
        /* ignore */
      }
      if (window.YT?.Player) resolve(window.YT);
      else reject(new Error('YT namespace missing after ready'));
    };
    const existing = document.querySelector(
      'script[src="' + IFRAME_API_URL + '"]',
    );
    if (existing) return;
    const tag = document.createElement('script');
    tag.src = IFRAME_API_URL;
    tag.async = true;
    document.head.appendChild(tag);
  });
  return apiPromise;
}

interface Props {
  sessionId: string;
  onClose: () => void;
}

const DRIFT_THRESHOLD_SECONDS = 2;

export function WatchTogetherModal({ sessionId, onClose }: Props) {
  const { t } = useTranslation();
  const { session, pushState, endSession, error, loading } = useWatchSession(sessionId);
  const { session: auth } = useAuth();
  const mountRef = useRef<HTMLDivElement | null>(null);
  const playerRef = useRef<YTPlayer | null>(null);
  const [playerReady, setPlayerReady] = useState(false);
  const ownerId = session?.ownerUserId ?? null;
  const isOwner = !!auth?.user.id && auth.user.id === ownerId;
  const ended = !!session?.endedAt;

  useEffect(() => {
    const onKey = (e: KeyboardEvent) => {
      if (e.key === 'Escape') onClose();
    };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);

  useEffect(() => {
    if (!session?.videoId || !mountRef.current) return;
    if (playerRef.current) return;
    let disposed = false;
    void loadIframeApi().then((YT) => {
      if (disposed || !mountRef.current) return;
      playerRef.current = new YT.Player(mountRef.current, {
        width: '100%',
        height: '100%',
        videoId: session.videoId,
        playerVars: { autoplay: 1, controls: isOwner ? 1 : 0, modestbranding: 1 },
        events: {
          onReady: () => setPlayerReady(true),
          onStateChange: (ev) => {
            if (!isOwner) return;
            const playing = ev.data === YT.PlayerState.PLAYING;
            const pos = ev.target.getCurrentTime();
            pushState({ playing, positionSeconds: pos, updatedAtMs: Date.now() });
          },
        },
      });
    }).catch((err) => {
      console.error('YouTube IFrame API failed', err);
    });
    return () => {
      disposed = true;
      try {
        playerRef.current?.destroy();
      } catch {
        /* ignore */
      }
      playerRef.current = null;
    };
  }, [session?.videoId, isOwner, pushState]);

  useEffect(() => {
    if (!isOwner || !playerReady) return;
    const id = window.setInterval(() => {
      const p = playerRef.current;
      if (!p) return;
      try {
        const state = p.getPlayerState();
        const playing = state === window.YT?.PlayerState.PLAYING;
        pushState({
          playing,
          positionSeconds: p.getCurrentTime(),
          updatedAtMs: Date.now(),
        });
      } catch {
        /* ignore */
      }
    }, 1000);
    return () => window.clearInterval(id);
  }, [isOwner, playerReady, pushState]);

  useEffect(() => {
    if (isOwner || !playerReady || !session) return;
    const p = playerRef.current;
    if (!p) return;
    const remoteAgeSec = Math.max(0, (Date.now() - session.currentState.updatedAtMs) / 1000);
    const projectedRemote = session.currentState.playing
      ? session.currentState.positionSeconds + remoteAgeSec
      : session.currentState.positionSeconds;
    let local = 0;
    try {
      local = p.getCurrentTime();
    } catch {
      return;
    }
    if (Math.abs(local - projectedRemote) > DRIFT_THRESHOLD_SECONDS) {
      try {
        p.seekTo(projectedRemote, true);
      } catch {
        /* ignore */
      }
    }
    try {
      const state = p.getPlayerState();
      const localPlaying = state === window.YT?.PlayerState.PLAYING;
      if (session.currentState.playing && !localPlaying) {
        p.playVideo();
      } else if (!session.currentState.playing && localPlaying) {
        p.pauseVideo();
      }
    } catch {
      /* ignore */
    }
  }, [isOwner, playerReady, session]);

  const handleClose = async () => {
    if (isOwner && !ended) {
      try {
        await endSession();
      } catch (err) {
        console.warn('endSession failed', err);
      }
    }
    onClose();
  };

  return (
    <div
      role="dialog"
      aria-modal="true"
      aria-label={t('app:watch.title', { defaultValue: 'Watch Together' })}
      className="fixed inset-0 z-[80] flex flex-col bg-black"
    >
      <header className="flex shrink-0 items-center justify-between border-b border-line/40 bg-surface-2 px-4 py-2">
        <h2 className="font-display text-sm font-semibold text-fg">
          {t('app:watch.title', { defaultValue: 'Watch Together' })}
          {ended && (
            <span className="ml-2 rounded-md bg-rose-500/15 px-1.5 py-0.5 text-[10px] font-semibold uppercase tracking-wide text-rose-600 dark:text-rose-300">
              {t('app:watch.ended', { defaultValue: 'Beendet' })}
            </span>
          )}
        </h2>
        <button
          type="button"
          onClick={() => void handleClose()}
          aria-label={t('app:watch.close', { defaultValue: 'Schließen' })}
          className="flex h-7 w-7 cursor-pointer items-center justify-center rounded-md text-fg-muted hover:bg-surface-3 hover:text-fg"
        >
          <XIcon className="h-3.5 w-3.5" />
        </button>
      </header>

      <div className="flex min-h-0 flex-1 items-center justify-center overflow-hidden bg-black p-4">
        {loading ? (
          <p className="text-sm text-fg-muted">
            {t('app:watch.loading', { defaultValue: 'Lädt…' })}
          </p>
        ) : error ? (
          <p className="text-sm text-rose-400">{error}</p>
        ) : !session ? (
          <p className="text-sm text-fg-muted">
            {t('app:watch.missing', { defaultValue: 'Session nicht gefunden.' })}
          </p>
        ) : (
          <div className="aspect-video w-full max-w-5xl">
            <div ref={mountRef} className="h-full w-full" />
          </div>
        )}
      </div>

      <footer className="flex shrink-0 items-center justify-between gap-3 border-t border-line/40 bg-surface-2 px-4 py-2 text-xs text-fg-muted">
        <span>
          {isOwner
            ? t('app:watch.you_are_host', { defaultValue: 'Du steuerst die Wiedergabe.' })
            : t('app:watch.you_are_guest', { defaultValue: 'Nur der Host kann steuern.' })}
        </span>
        <span>
          {session?.currentState.playing
            ? t('app:watch.playing', { defaultValue: '▶ Läuft' })
            : t('app:watch.paused', { defaultValue: '⏸ Pause' })}
        </span>
      </footer>
    </div>
  );
}
