// 재생 엔진: directive(재생 지시)를 받아 영상/유튜브/대기화면을 렌더링한다.
// 플레이어 화면과 CMS 미리보기가 동일하게 사용 → "지금 나가는 화면"이 일치한다.

function weatherEmoji(code) {
  if (code === 0) return '☀️';
  if (code <= 3) return '⛅';
  if (code <= 48) return '🌫️';
  if (code <= 67) return '🌧️';
  if (code <= 77) return '🌨️';
  if (code <= 82) return '🌦️';
  if (code <= 86) return '🌨️';
  return '⛈️';
}
function hexToRgba(hex, a) {
  hex = (hex || '#000').replace('#', '');
  if (hex.length === 3) hex = hex.split('').map((c) => c + c).join('');
  const r = parseInt(hex.slice(0, 2), 16) || 0, g = parseInt(hex.slice(2, 4), 16) || 0, b = parseInt(hex.slice(4, 6), 16) || 0;
  return `rgba(${r},${g},${b},${a})`;
}

export class PlaybackEngine {
  constructor(stageEl, opts = {}) {
    this.stage = stageEl;           // 실제 해상도 크기의 무대 div
    this.muted = opts.muted ?? true;
    this.onNowPlaying = opts.onNowPlaying || (() => {});
    this.directive = null;
    this.playlist = [];
    this.index = 0;
    this.ytPlayer = null;
    this.ytReady = false;
    this.clockTimer = null;
    this.imageTimer = null;

    // 내부 요소 구성
    this.stage.innerHTML = '';
    this.scaleMode = 'contain';
    this.videoEl = document.createElement('video');
    this.videoEl.playsInline = true;
    this.videoEl.muted = this.muted;
    this.videoEl.style.cssText = 'width:100%;height:100%;object-fit:contain;background:#000;display:none';
    this.stage.appendChild(this.videoEl);

    this.imgEl = document.createElement('img');
    this.imgEl.style.cssText = 'position:absolute;inset:0;width:100%;height:100%;object-fit:contain;background:#000;display:none';
    this.stage.appendChild(this.imgEl);

    this.ytWrap = document.createElement('div');
    // pointer-events:none → 유튜브 컨트롤/제목이 hover·클릭으로 뜨지 않게, 일시정지도 불가
    this.ytWrap.style.cssText = 'position:absolute;inset:0;display:none;pointer-events:none';
    this.ytWrap.innerHTML = '<div id="yt-target-' + Math.random().toString(36).slice(2) + '" style="width:100%;height:100%"></div>';
    this.ytTargetId = this.ytWrap.firstChild.id;
    this.stage.appendChild(this.ytWrap);

    this.idleEl = document.createElement('div');
    this.idleEl.style.cssText =
      'position:absolute;inset:0;display:none;align-items:center;justify-content:center;flex-direction:column;background:#000;color:#fff;font-family:system-ui,sans-serif';
    this.stage.appendChild(this.idleEl);

    // 오버레이 레이어 (자막 티커 / 시계 위젯) — 모든 콘텐츠 위에 표시
    this.overlayEl = document.createElement('div');
    this.overlayEl.style.cssText = 'position:absolute;inset:0;pointer-events:none;z-index:5;overflow:hidden';
    this.stage.appendChild(this.overlayEl);
    this.tickerBar = document.createElement('div');
    this.tickerBar.style.cssText = 'position:absolute;left:0;right:0;display:none;overflow:hidden;white-space:nowrap';
    this.tickerInner = document.createElement('div');
    this.tickerInner.style.cssText = 'display:inline-block;padding-left:100%;white-space:nowrap;will-change:transform';
    this.tickerBar.appendChild(this.tickerInner);
    this.overlayEl.appendChild(this.tickerBar);
    this.clockWidget = document.createElement('div');
    this.clockWidget.style.cssText = 'position:absolute;display:none;font-family:system-ui,sans-serif;font-weight:800;color:#fff;text-shadow:0 2px 6px rgba(0,0,0,.85);line-height:1.1';
    this.overlayEl.appendChild(this.clockWidget);
    this.weatherWidget = document.createElement('div');
    this.weatherWidget.style.cssText = 'position:absolute;display:none;font-family:system-ui,sans-serif;font-weight:800;color:#fff;text-shadow:0 2px 6px rgba(0,0,0,.85);line-height:1.1';
    this.overlayEl.appendChild(this.weatherWidget);
    if (!document.getElementById('sig-ticker-kf')) {
      const st = document.createElement('style');
      st.id = 'sig-ticker-kf';
      st.textContent = '@keyframes sig-ticker{0%{transform:translateX(0)}100%{transform:translateX(-100%)}}';
      document.head.appendChild(st);
    }
    this.overlayTimer = null;
    this._lastTickerKey = '';

    this.videoEl.addEventListener('ended', () => this._next());
    this.videoEl.addEventListener('error', () => setTimeout(() => this._next(), 1500));

    this._loadYT();
  }

  _loadYT() {
    if (window.YT && window.YT.Player) { this.ytReady = true; return; }
    if (!document.getElementById('yt-iframe-api')) {
      const tag = document.createElement('script');
      tag.id = 'yt-iframe-api';
      tag.src = 'https://www.youtube.com/iframe_api';
      document.head.appendChild(tag);
    }
    const prev = window.onYouTubeIframeAPIReady;
    window.onYouTubeIframeAPIReady = () => { if (prev) prev(); this.ytReady = true; };
  }

  setMuted(m) {
    this.muted = m;
    this.videoEl.muted = m;
    if (this.ytPlayer) { m ? this.ytPlayer.mute() : this.ytPlayer.unMute(); }
  }

  // directive 적용
  apply(directive) {
    const prevKey = this.directive ? this._key(this.directive) : null;
    const nextKey = this._key(directive);
    this.directive = directive;
    this._applyBrightness(directive.brightness);
    this._applyScaleMode(directive.scaleMode || 'contain');
    this._applyOverlay(directive.overlay || {}, directive.resolution);
    if (prevKey === nextKey) return; // 재생 목록 동일 → 오버레이·밝기만 갱신하고 리로드 안 함

    this.playlist = directive.playlist || [];
    this.index = 0;
    this._stopClock();

    if (!this.playlist.length) { this._showIdle(directive); return; }
    this._playCurrent();
  }

  _key(d) {
    return JSON.stringify({ mode: d.mode, ids: (d.playlist || []).map((m) => m.id) });
  }

  _applyBrightness(b) {
    const factor = Math.max(0, Math.min(100, b ?? 100)) / 100;
    this.stage.style.filter = `brightness(${factor})`;
  }

  // 스케일 방식: contain(여백,왜곡없음/1:1) | cover(꽉채움,잘림) | fill(늘림)
  _applyScaleMode(mode) {
    this.scaleMode = mode;
    // 비디오/이미지는 object-fit 으로 정확히 제어 (해상도가 정확히 맞으면 contain/cover 모두 1:1)
    this.videoEl.style.objectFit = mode === 'fill' ? 'fill' : mode;
    this.imgEl.style.objectFit = mode === 'fill' ? 'fill' : mode;
    // 유튜브(iframe)는 채움 모드일 때 화면을 덮도록 확대
    if (mode === 'cover') {
      this.ytWrap.style.transform = 'scale(1.34)'; // 16:9 iframe이 대략 화면을 덮도록
    } else {
      this.ytWrap.style.transform = 'none';
    }
  }

  _applyOverlay(ov, res) {
    const H = (res && res.height) || 1080;
    // --- 자막 티커 ---
    const t = ov.ticker || {};
    if (t.enabled && String(t.text || '').trim()) {
      const barH = Math.max(28, Math.round(H * 0.075));
      this.tickerBar.style.display = 'block';
      this.tickerBar.style.height = barH + 'px';
      if (t.position === 'top') { this.tickerBar.style.top = '0'; this.tickerBar.style.bottom = 'auto'; }
      else { this.tickerBar.style.bottom = '0'; this.tickerBar.style.top = 'auto'; }
      this.tickerBar.style.background = hexToRgba(t.bg || '#000000', (t.opacity ?? 65) / 100);
      this.tickerInner.style.color = t.color || '#ffffff';
      this.tickerInner.style.fontSize = Math.round(barH * 0.55) + 'px';
      this.tickerInner.style.lineHeight = barH + 'px';
      this.tickerInner.style.fontWeight = '700';
      const key = String(t.text) + '|' + (t.speedSec || 20);
      if (key !== this._lastTickerKey) {
        this._lastTickerKey = key;
        this.tickerInner.textContent = t.text;
        this.tickerInner.style.animation = 'none';
        void this.tickerInner.offsetWidth; // reflow로 애니메이션 재시작
        this.tickerInner.style.animation = `sig-ticker ${Math.max(4, t.speedSec || 20)}s linear infinite`;
      }
    } else {
      this.tickerBar.style.display = 'none';
      this._lastTickerKey = '';
    }
    // --- 시계 위젯 ---
    const c = ov.clock || {};
    if (c.enabled) {
      const pad = Math.round(H * 0.03);
      const pos = c.position || 'top-right';
      this.clockWidget.style.display = 'block';
      this.clockWidget.style.fontSize = Math.round(H * 0.045) + 'px';
      this.clockWidget.style.top = pos.startsWith('top') ? pad + 'px' : 'auto';
      this.clockWidget.style.bottom = pos.startsWith('bottom') ? pad + 'px' : 'auto';
      this.clockWidget.style.left = pos.endsWith('left') ? pad + 'px' : 'auto';
      this.clockWidget.style.right = pos.endsWith('right') ? pad + 'px' : 'auto';
      this.clockWidget.style.textAlign = pos.endsWith('left') ? 'left' : 'right';
      this._clockShowDate = c.showDate !== false;
      this._renderClockWidget();
      if (!this.overlayTimer) this.overlayTimer = setInterval(() => this._renderClockWidget(), 1000);
    } else {
      this.clockWidget.style.display = 'none';
      if (this.overlayTimer) { clearInterval(this.overlayTimer); this.overlayTimer = null; }
    }
    // --- 날씨 위젯 ---
    const wx = ov.weather || {};
    if (wx.enabled && wx.temp !== undefined && wx.temp !== null) {
      const pad = Math.round(H * 0.03);
      const pos = wx.position || 'top-left';
      this.weatherWidget.style.display = 'block';
      this.weatherWidget.style.fontSize = Math.round(H * 0.042) + 'px';
      this.weatherWidget.style.top = pos.startsWith('top') ? pad + 'px' : 'auto';
      this.weatherWidget.style.bottom = pos.startsWith('bottom') ? pad + 'px' : 'auto';
      this.weatherWidget.style.left = pos.endsWith('left') ? pad + 'px' : 'auto';
      this.weatherWidget.style.right = pos.endsWith('right') ? pad + 'px' : 'auto';
      this.weatherWidget.style.textAlign = pos.endsWith('left') ? 'left' : 'right';
      this.weatherWidget.innerHTML = `${weatherEmoji(wx.code)} ${wx.temp}°<span style="font-size:.62em;font-weight:600;opacity:.9;margin-left:.35em">${wx.label || ''}</span>`;
    } else {
      this.weatherWidget.style.display = 'none';
    }
  }

  _renderClockWidget() {
    const now = new Date();
    const p = (n) => String(n).padStart(2, '0');
    let html = `<div>${p(now.getHours())}:${p(now.getMinutes())}:${p(now.getSeconds())}</div>`;
    if (this._clockShowDate) {
      html += `<div style="font-size:.55em;font-weight:600;opacity:.9">${now.getFullYear()}.${p(now.getMonth() + 1)}.${p(now.getDate())}</div>`;
    }
    this.clockWidget.innerHTML = html;
  }

  _showIdle(directive) {
    this._clearImageTimer();
    this.imgEl.style.display = 'none';
    this.videoEl.style.display = 'none';
    this.videoEl.pause();
    this.ytWrap.style.display = 'none';
    this._destroyYT();
    this.idleEl.style.display = 'flex';
    if (directive.mode !== 'off' && directive.idleMode === 'clock') {
      this._startClock();
    } else {
      this.idleEl.innerHTML = ''; // 검은 화면 (전원 취침 포함)
    }
  }

  _startClock() {
    const render = () => {
      const now = new Date();
      // 윗줄: 2026년 7월 29일
      const dateStr = `${now.getFullYear()}년 ${now.getMonth() + 1}월 ${now.getDate()}일`;
      // 아랫줄: 오전 09:01:02
      const h = now.getHours();
      const ampm = h < 12 ? '오전' : '오후';
      const h12 = ((h + 11) % 12) + 1;
      const p = (n) => String(n).padStart(2, '0');
      const timeStr = `${ampm} ${p(h12)}:${p(now.getMinutes())}:${p(now.getSeconds())}`;
      this.idleEl.innerHTML =
        `<div style="font-size:6vmin;font-weight:700;letter-spacing:1px">${dateStr}</div>
         <div style="font-size:11vmin;font-weight:800;letter-spacing:2px;font-variant-numeric:tabular-nums;margin-top:1vmin">${timeStr}</div>`;
    };
    render();
    this.clockTimer = setInterval(render, 1000);
  }

  _stopClock() { if (this.clockTimer) { clearInterval(this.clockTimer); this.clockTimer = null; } }

  _next() {
    if (!this.playlist.length) return;
    this.index = (this.index + 1) % this.playlist.length;
    this._playCurrent();
  }

  _clearImageTimer() { if (this.imageTimer) { clearTimeout(this.imageTimer); this.imageTimer = null; } }

  _playCurrent() {
    const item = this.playlist[this.index];
    if (!item) return;
    this._stopClock();
    this._clearImageTimer();
    this.idleEl.style.display = 'none';
    this.onNowPlaying(item, this.index);

    if (item.type === 'youtube') {
      this._playYouTube(item);
    } else if (item.kind === 'image') {
      this._playImage(item);
    } else {
      this._playVideo(item);
    }
  }

  _playImage(item) {
    this.videoEl.style.display = 'none';
    this.videoEl.pause();
    this.ytWrap.style.display = 'none';
    this._destroyYT();
    this.imgEl.style.display = 'block';
    const src = item.type === 'upload' ? `/media/${item.src}` : `/api/stream/${item.id}`;
    this.imgEl.src = src;
    // 여러 장이면 표시 시간(초) 후 다음으로, 한 장이면 계속 표시
    if (this.playlist.length > 1) {
      const sec = item.durationSec || 8;
      this.imageTimer = setTimeout(() => this._next(), sec * 1000);
    }
  }

  _playVideo(item) {
    this.imgEl.style.display = 'none';
    this.ytWrap.style.display = 'none';
    this._destroyYT();
    this.videoEl.style.display = 'block';
    const src = item.type === 'upload' ? `/media/${item.src}` : `/api/stream/${item.id}`;
    // 단일 항목이면 자체 loop, 여러 항목이면 ended 이벤트로 순환
    this.videoEl.loop = this.playlist.length === 1;
    this.videoEl.src = src;
    this.videoEl.muted = this.muted;
    const p = this.videoEl.play();
    if (p && p.catch) p.catch(() => {/* 자동재생 차단 시 무음으로 재시도 */
      this.videoEl.muted = true; this.videoEl.play().catch(() => {});
    });
  }

  _playYouTube(item) {
    this.imgEl.style.display = 'none';
    this.videoEl.style.display = 'none';
    this.videoEl.pause();
    this.ytWrap.style.display = 'block';

    const start = () => {
      this._destroyYT();
      // 재생 대상 div 재생성 (destroy 후 사라짐)
      this.ytWrap.innerHTML = `<div id="${this.ytTargetId}" style="width:100%;height:100%"></div>`;
      this._ytForcePlay = true;
      this.ytPlayer = new window.YT.Player(this.ytTargetId, {
        videoId: item.src,
        playerVars: {
          autoplay: 1, controls: 0, mute: this.muted ? 1 : 0, rel: 0, modestbranding: 1, playsinline: 1,
          disablekb: 1, fs: 0, iv_load_policy: 3, cc_load_policy: 0, showinfo: 0,
          loop: this.playlist.length === 1 ? 1 : 0, playlist: this.playlist.length === 1 ? item.src : undefined,
        },
        events: {
          onReady: (e) => { this.muted ? e.target.mute() : e.target.unMute(); e.target.playVideo(); },
          onStateChange: (e) => {
            const YT = window.YT.PlayerState;
            if (e.data === YT.ENDED) { if (this.playlist.length > 1) this._next(); }
            // 무조건 재생: 예기치 않게 멈추면(일시정지/버퍼링 후 정지) 즉시 재생 재개
            else if (e.data === YT.PAUSED && this._ytForcePlay) { try { e.target.playVideo(); } catch {} }
          },
          onError: () => setTimeout(() => this._next(), 1500),
        },
      });
    };

    if (this.ytReady && window.YT && window.YT.Player) start();
    else {
      const wait = setInterval(() => {
        if (this.ytReady && window.YT && window.YT.Player) { clearInterval(wait); start(); }
      }, 200);
    }
  }

  _destroyYT() {
    this._ytForcePlay = false; // 전환 중 자동 재개가 파괴된 플레이어를 건드리지 않도록
    if (this.ytPlayer) { try { this.ytPlayer.destroy(); } catch {} this.ytPlayer = null; }
  }

  // 현재 화면 프레임을 캡처(JPEG dataURL). 유튜브/대기화면은 캡처 불가.
  captureFrame(maxW = 720) {
    try {
      let src = null, sw = 0, sh = 0, kind = '';
      if (this.videoEl.style.display !== 'none' && this.videoEl.videoWidth) { src = this.videoEl; sw = this.videoEl.videoWidth; sh = this.videoEl.videoHeight; kind = 'video'; }
      else if (this.imgEl.style.display !== 'none' && this.imgEl.naturalWidth) { src = this.imgEl; sw = this.imgEl.naturalWidth; sh = this.imgEl.naturalHeight; kind = 'image'; }
      else if (this.ytWrap.style.display !== 'none') { return { unavailable: true, kind: 'youtube' }; }
      else { return { unavailable: true, kind: 'idle' }; }
      const scale = Math.min(1, maxW / sw);
      const w = Math.max(1, Math.round(sw * scale)), h = Math.max(1, Math.round(sh * scale));
      const cv = document.createElement('canvas'); cv.width = w; cv.height = h;
      cv.getContext('2d').drawImage(src, 0, 0, w, h);
      return { dataUrl: cv.toDataURL('image/jpeg', 0.6), kind };
    } catch (e) {
      return { unavailable: true, error: e.message };
    }
  }
}
