/**
 * Style & Layout Settings Manager
 */
class StyleEditor {
  constructor(state) {
    this.state = state;
    this.initFontOptions();
    this.bindInputs();
    this.bindPresets();
    this.state.on("styleChanged", (style) => this.syncUI(style));
    this.state.on("projectLoaded", () => this.syncUI(this.state.style));
  }

  async initFontOptions() {
    const select = document.getElementById("font-family-select");
    if (!select) return;

    try {
      const res = await fetch("/api/fonts");
      const data = await res.json();
      select.innerHTML = "";
      (data.fonts || []).forEach(f => {
        const opt = document.createElement("option");
        opt.value = f.name;
        opt.innerText = f.displayName;
        if (f.name.toLowerCase() === this.state.style.fontFamily.toLowerCase()) {
          opt.selected = true;
        }
        select.appendChild(opt);
      });
    } catch (e) {
      console.log("Could not load system fonts:", e);
    }
  }

  bindInputs() {
    const bindVal = (id, prop, isNumber = false, isFloat = false) => {
      const el = document.getElementById(id);
      if (!el) return;
      el.addEventListener("input", (e) => {
        let val = e.target.value;
        if (isNumber) val = parseInt(val, 10);
        if (isFloat) val = parseFloat(val);
        const update = {};
        update[prop] = val;
        this.state.updateStyle(update);

        // Update companion display label if exists
        const labelEl = document.getElementById(`${id}-val`);
        if (labelEl) labelEl.innerText = val;
      });
    };

    const bindColor = (id, prop) => {
      const el = document.getElementById(id);
      if (!el) return;
      el.addEventListener("input", (e) => {
        const update = {};
        update[prop] = e.target.value;
        this.state.updateStyle(update);
      });
    };

    // Font & text
    const fontSel = document.getElementById("font-family-select");
    if (fontSel) {
      fontSel.addEventListener("change", (e) => {
        this.state.updateStyle({ fontFamily: e.target.value });
      });
    }

    // Custom Font File Upload (.ttf / .otf / .woff)
    const btnUploadFont = document.getElementById("btn-upload-font");
    const fontFileInput = document.getElementById("font-file-input");
    if (btnUploadFont && fontFileInput) {
      btnUploadFont.addEventListener("click", () => fontFileInput.click());
      fontFileInput.addEventListener("change", async (e) => {
        const file = e.target.files[0];
        if (!file) return;

        const formData = new FormData();
        formData.append("file", file);

        btnUploadFont.innerText = "⏳ 載入字型中...";
        try {
          const res = await fetch("/api/upload-font", {
            method: "POST",
            body: formData
          });
          const data = await res.json();
          btnUploadFont.innerText = "📁 匯入字型檔";

          // Dynamically load font into document
          const fontFace = new FontFace(data.familyName, `url("${data.fontUrl}")`);
          await fontFace.load();
          document.fonts.add(fontFace);

          // Add to select if not exists
          let existingOpt = Array.from(fontSel.options).find(o => o.value === data.familyName);
          if (!existingOpt) {
            const opt = document.createElement("option");
            opt.value = data.familyName;
            opt.innerText = `★ 自訂: ${data.familyName} (${data.fileName})`;
            fontSel.insertBefore(opt, fontSel.firstChild);
          }
          fontSel.value = data.familyName;

          this.state.updateStyle({
            fontFamily: data.familyName,
            customFontUrl: data.fontUrl,
            customFontName: data.familyName
          });
          alert(`成功載入字型：${data.familyName}！`);
        } catch (err) {
          alert("字型載入失敗：" + err);
          btnUploadFont.innerText = "📁 匯入字型檔";
        }
      });
    }

    bindVal("font-size-slider", "fontSize", true);
    bindVal("letter-spacing-slider", "letterSpacing", true);

    const boldCheck = document.getElementById("bold-toggle");
    if (boldCheck) {
      boldCheck.addEventListener("change", (e) => {
        this.state.updateStyle({ bold: e.target.checked });
      });
    }

    // Base colors
    bindColor("base-color-input", "baseColor");
    bindColor("base-outline-color-input", "baseOutlineColor");
    bindVal("outline-width-slider", "outlineWidth", true);
    bindVal("shadow-width-slider", "shadowWidth", true);

    // Singer wipe colors
    bindColor("male-wipe-color", "maleWipeColor");
    bindColor("male-outline-color", "maleOutlineColor");
    bindColor("female-wipe-color", "femaleWipeColor");
    bindColor("female-outline-color", "femaleOutlineColor");
    bindColor("duet-wipe-color", "duetWipeColor");
    bindColor("duet-outline-color", "duetOutlineColor");

    // Default singer selector & apply
    const defaultSingerSel = document.getElementById("default-singer-select");
    if (defaultSingerSel) {
      defaultSingerSel.addEventListener("change", (e) => {
        this.state.updateStyle({ defaultSinger: e.target.value });
        const lyricsSel = document.getElementById("lyrics-default-singer");
        if (lyricsSel) lyricsSel.value = e.target.value;
      });
    }

    const btnApplyDefaultSinger = document.getElementById("btn-apply-default-singer");
    if (btnApplyDefaultSinger) {
      btnApplyDefaultSinger.addEventListener("click", () => {
        const singer = this.state.style.defaultSinger || "duet";
        const label = singer === "male" ? "男唱" : singer === "female" ? "女唱" : "合唱";
        if (confirm(`確定將全曲所有句子都設定為【${label}】嗎？`)) {
          (this.state.sentences || []).forEach(s => s.singer = singer);
          this.state.emit("sentencesChanged", this.state.sentences);
        }
      });
    }

    const lyricsDefaultSingerSel = document.getElementById("lyrics-default-singer");
    if (lyricsDefaultSingerSel) {
      lyricsDefaultSingerSel.addEventListener("change", (e) => {
        this.state.updateStyle({ defaultSinger: e.target.value });
        if (defaultSingerSel) defaultSingerSel.value = e.target.value;
      });
    }

    // Positioning Sliders
    const line1X = document.getElementById("line1-x-slider");
    const line1Y = document.getElementById("line1-y-slider");
    const line2X = document.getElementById("line2-x-slider");
    const line2Y = document.getElementById("line2-y-slider");

    if (line1X) {
      line1X.addEventListener("input", (e) => {
        const pct = parseInt(e.target.value, 10) / 100;
        this.state.updateStyle({ line1X: pct });
        document.getElementById("line1-x-val").innerText = `${e.target.value}%`;
      });
    }
    if (line1Y) {
      line1Y.addEventListener("input", (e) => {
        const pct = parseInt(e.target.value, 10) / 100;
        this.state.updateStyle({ line1Y: pct });
        document.getElementById("line1-y-val").innerText = `${e.target.value}%`;
      });
    }
    if (line2X) {
      line2X.addEventListener("input", (e) => {
        const pct = parseInt(e.target.value, 10) / 100;
        this.state.updateStyle({ line2X: pct });
        document.getElementById("line2-x-val").innerText = `${e.target.value}%`;
      });
    }
    if (line2Y) {
      line2Y.addEventListener("input", (e) => {
        const pct = parseInt(e.target.value, 10) / 100;
        this.state.updateStyle({ line2Y: pct });
        document.getElementById("line2-y-val").innerText = `${e.target.value}%`;
      });
    }

    // Toggle drag mode on video
    const toggleDragBtn = document.getElementById("btn-toggle-drag-layer");
    const dragLayer = document.getElementById("position-drag-layer");
    if (toggleDragBtn && dragLayer) {
      toggleDragBtn.addEventListener("click", () => {
        this.state.dragPositionsMode = !this.state.dragPositionsMode;
        dragLayer.style.display = this.state.dragPositionsMode ? "block" : "none";
        toggleDragBtn.classList.toggle("btn-primary", this.state.dragPositionsMode);
        toggleDragBtn.innerText = this.state.dragPositionsMode ? "✓ 結束畫面拖曳調整" : "🖐 在預覽畫面上拖曳定位";
      });
    }

    // Fade in/out settings
    const fadeToggle = document.getElementById("fade-toggle");
    if (fadeToggle) {
      fadeToggle.addEventListener("change", (e) => {
        this.state.updateStyle({ enableFade: e.target.checked });
      });
    }

    const fadeDurSlider = document.getElementById("fade-duration-slider");
    if (fadeDurSlider) {
      fadeDurSlider.addEventListener("input", (e) => {
        const dur = Math.round(parseInt(e.target.value, 10)) / 10;
        this.state.updateStyle({ fadeDuration: dur });
        const valLabel = document.getElementById("fade-duration-slider-val");
        if (valLabel) valLabel.innerText = `${dur}s`;
      });
    }

    // Countdown Dots settings
    const countdownCheck = document.getElementById("countdown-toggle");
    if (countdownCheck) {
      countdownCheck.addEventListener("change", (e) => {
        this.state.updateStyle({ enableCountdown: e.target.checked });
      });
    }

    const bpmSlider = document.getElementById("song-bpm-slider");
    if (bpmSlider) {
      const updateBpm = (val) => {
        const bpm = parseInt(val, 10) || 80;
        const bpmVal = document.getElementById("song-bpm-val");
        if (bpmVal) bpmVal.innerText = `${bpm} BPM`;
        const bpmCalc = document.getElementById("bpm-calc-text");
        if (bpmCalc) {
          const beatSec = (60.0 / bpm).toFixed(2);
          bpmCalc.innerText = `每拍約 ${beatSec} 秒 (依歌曲拍子倒數)`;
        }
        this.state.updateStyle({ bpm });
      };
      bpmSlider.addEventListener("input", (e) => updateBpm(e.target.value));
      bpmSlider.addEventListener("change", (e) => updateBpm(e.target.value));
    }

    const tapBtn = document.getElementById("btn-tap-tempo");
    let tapTimes = [];
    let tapResetTimer = null;
    if (tapBtn) {
      tapBtn.addEventListener("click", () => {
        const now = performance.now();
        if (tapTimes.length > 0 && (now - tapTimes[tapTimes.length - 1]) > 2500) {
          tapTimes = [];
        }
        tapTimes.push(now);
        if (tapTimes.length > 8) tapTimes.shift();

        if (tapTimes.length >= 2) {
          const intervals = [];
          for (let i = 1; i < tapTimes.length; i++) {
            intervals.push(tapTimes[i] - tapTimes[i - 1]);
          }
          const avgMs = intervals.reduce((a, b) => a + b, 0) / intervals.length;
          let detectedBpm = Math.round(60000 / avgMs);
          if (detectedBpm < 40) detectedBpm = 40;
          if (detectedBpm > 200) detectedBpm = 200;

          if (bpmSlider) bpmSlider.value = detectedBpm;
          const bpmVal = document.getElementById("song-bpm-val");
          if (bpmVal) bpmVal.innerText = `${detectedBpm} BPM`;
          const bpmCalc = document.getElementById("bpm-calc-text");
          if (bpmCalc) {
            const beatSec = (60.0 / detectedBpm).toFixed(2);
            bpmCalc.innerText = `每拍約 ${beatSec} 秒 (依歌曲拍子倒數)`;
          }
          this.state.updateStyle({ bpm: detectedBpm });

          tapBtn.innerText = `🎵 測得 ${detectedBpm} BPM!`;
          tapBtn.style.background = "rgba(0, 230, 118, 0.25)";
          tapBtn.style.borderColor = "var(--accent-green)";
          tapBtn.style.color = "var(--accent-green)";
          clearTimeout(tapResetTimer);
          tapResetTimer = setTimeout(() => {
            tapBtn.innerText = "🎵 點擊測速 (Tap)";
            tapBtn.style.background = "rgba(0, 210, 255, 0.12)";
            tapBtn.style.borderColor = "var(--accent-cyan)";
            tapBtn.style.color = "var(--accent-cyan)";
          }, 1200);
        } else {
          tapBtn.innerText = "🎵 請再點 1 次...";
        }
      });
    }

    const dotCountSel = document.getElementById("countdown-dot-count");
    if (dotCountSel) {
      dotCountSel.addEventListener("change", (e) => {
        this.state.updateStyle({ countdownDotCount: parseInt(e.target.value, 10) });
      });
    }

    bindVal("countdown-dot-size", "countdownDotSize", true);
    bindVal("countdown-offset-y", "countdownOffsetY", true);
    bindVal("countdown-offset-x", "countdownOffsetX", true);

    const ghostCheck = document.getElementById("show-ghost-toggle");
    if (ghostCheck) {
      ghostCheck.addEventListener("change", (e) => {
        this.state.updateStyle({ showFadedGhost: e.target.checked });
      });
    }

    // Singer dot colors
    bindColor("male-dot-fill", "maleDotFill");
    bindColor("male-dot-outline", "maleDotOutline");
    bindVal("male-dot-outline-width", "maleDotOutlineWidth", true);

    bindColor("female-dot-fill", "femaleDotFill");
    bindColor("female-dot-outline", "femaleDotOutline");
    bindVal("female-dot-outline-width", "femaleDotOutlineWidth", true);

    bindColor("duet-dot-fill", "duetDotFill");
    bindColor("duet-dot-outline", "duetDotOutline");
    bindVal("duet-dot-outline-width", "duetDotOutlineWidth", true);
  }

  bindPresets() {
    const presetClassic = document.getElementById("preset-classic");
    const presetCenter = document.getElementById("preset-center");
    const presetLeftStack = document.getElementById("preset-left-stack");

    if (presetClassic) {
      presetClassic.addEventListener("click", () => {
        this.state.updateStyle({
          line1X: 0.08,
          line1Y: 0.68,
          line2X: 0.92,
          line2Y: 0.84
        });
      });
    }

    if (presetCenter) {
      presetCenter.addEventListener("click", () => {
        this.state.updateStyle({
          line1X: 0.15,
          line1Y: 0.74,
          line2X: 0.85,
          line2Y: 0.86
        });
      });
    }

    if (presetLeftStack) {
      presetLeftStack.addEventListener("click", () => {
        this.state.updateStyle({
          line1X: 0.08,
          line1Y: 0.72,
          line2X: 0.92,
          line2Y: 0.85
        });
      });
    }

    // Flash autosave indicator when settings are saved
    this.state.on("settingsSaved", () => {
      const el = document.getElementById("autosave-status");
      if (el) {
        el.classList.add("show");
        clearTimeout(this._autosaveTimer);
        this._autosaveTimer = setTimeout(() => el.classList.remove("show"), 1500);
      }
    });
  }

  syncUI(style) {
    const setVal = (id, val) => {
      const el = document.getElementById(id);
      if (el) el.value = val;
    };
    const setLabel = (id, val) => {
      const el = document.getElementById(id);
      if (el) el.innerText = val;
    };

    // Ensure custom font is present in select if active
    const fontSel = document.getElementById("font-family-select");
    if (fontSel && style.fontFamily) {
      let opt = Array.from(fontSel.options).find(o => o.value === style.fontFamily);
      if (!opt) {
        opt = document.createElement("option");
        opt.value = style.fontFamily;
        opt.innerText = style.customFontName ? `★ 自訂: ${style.customFontName}` : style.fontFamily;
        fontSel.appendChild(opt);
      }
      fontSel.value = style.fontFamily;
    }

    setVal("font-size-slider", style.fontSize);
    setLabel("font-size-slider-val", `${style.fontSize}px`);

    setVal("letter-spacing-slider", style.letterSpacing !== undefined ? style.letterSpacing : 2);
    setLabel("letter-spacing-slider-val", `${style.letterSpacing !== undefined ? style.letterSpacing : 2}px`);

    const boldCheck = document.getElementById("bold-toggle");
    if (boldCheck) boldCheck.checked = !!style.bold;

    setVal("base-color-input", style.baseColor);
    setVal("base-outline-color-input", style.baseOutlineColor);
    setVal("outline-width-slider", style.outlineWidth);
    setLabel("outline-width-slider-val", `${style.outlineWidth}px`);
    setVal("shadow-width-slider", style.shadowWidth);
    setLabel("shadow-width-slider-val", `${style.shadowWidth}px`);

    setVal("male-wipe-color", style.maleWipeColor);
    setVal("male-outline-color", style.maleOutlineColor || "#003366");
    setVal("female-wipe-color", style.femaleWipeColor);
    setVal("female-outline-color", style.femaleOutlineColor || "#660033");
    setVal("duet-wipe-color", style.duetWipeColor);
    setVal("duet-outline-color", style.duetOutlineColor || "#004D26");

    setVal("default-singer-select", style.defaultSinger || "duet");
    setVal("lyrics-default-singer", style.defaultSinger || "duet");

    const l1x = Math.round(style.line1X * 100);
    const l1y = Math.round(style.line1Y * 100);
    const l2x = Math.round(style.line2X * 100);
    const l2y = Math.round(style.line2Y * 100);

    setVal("line1-x-slider", l1x);
    setLabel("line1-x-val", `${l1x}%`);
    setVal("line1-y-slider", l1y);
    setLabel("line1-y-val", `${l1y}%`);

    setVal("line2-x-slider", l2x);
    setLabel("line2-x-val", `${l2x}%`);
    setVal("line2-y-slider", l2y);
    setLabel("line2-y-val", `${l2y}%`);

    const fadeToggle = document.getElementById("fade-toggle");
    if (fadeToggle) fadeToggle.checked = (style.enableFade !== false);

    const fadeDur = (typeof style.fadeDuration === "number") ? style.fadeDuration : 0.4;
    setVal("fade-duration-slider", Math.round(fadeDur * 10));
    setLabel("fade-duration-slider-val", `${fadeDur}s`);

    const countdownCheck = document.getElementById("countdown-toggle");
    if (countdownCheck) countdownCheck.checked = !!style.enableCountdown;

    const bpm = style.bpm || 80;
    setVal("song-bpm-slider", bpm);
    setLabel("song-bpm-val", `${bpm} BPM`);
    const bpmCalc = document.getElementById("bpm-calc-text");
    if (bpmCalc) {
      const beatSec = (60.0 / bpm).toFixed(2);
      bpmCalc.innerText = `每拍約 ${beatSec} 秒 (依歌曲拍子倒數)`;
    }

    setVal("countdown-dot-count", style.countdownDotCount || 4);
    setVal("countdown-dot-size", style.countdownDotSize || 22);
    setLabel("countdown-dot-size-val", `${style.countdownDotSize || 22}px`);
    setVal("countdown-offset-y", style.countdownOffsetY || -46);
    setLabel("countdown-offset-y-val", `${style.countdownOffsetY || -46}px`);
    setVal("countdown-offset-x", style.countdownOffsetX || 10);
    setLabel("countdown-offset-x-val", `${style.countdownOffsetX || 10}px`);

    const ghostCheck = document.getElementById("show-ghost-toggle");
    if (ghostCheck) ghostCheck.checked = (style.showFadedGhost !== false);

    setVal("male-dot-fill", style.maleDotFill || "#0055FF");
    setVal("male-dot-outline", style.maleDotOutline || "#FFFFFF");
    setVal("male-dot-outline-width", style.maleDotOutlineWidth || 3);

    setVal("female-dot-fill", style.femaleDotFill || "#FF4081");
    setVal("female-dot-outline", style.femaleDotOutline || "#FFFFFF");
    setVal("female-dot-outline-width", style.femaleDotOutlineWidth || 3);

    setVal("duet-dot-fill", style.duetDotFill || "#00E676");
    setVal("duet-dot-outline", style.duetDotOutline || "#FFFFFF");
    setVal("duet-dot-outline-width", style.duetDotOutlineWidth || 3);
  }

  syncToState() {
    const s = (id) => document.getElementById(id);
    const getVal = (id, fallback) => { const el = s(id); return el ? el.value : fallback; };
    const getNum = (id, fallback) => { const el = s(id); return el ? (parseFloat(el.value) || 0) : fallback; };
    const getInt = (id, fallback) => { const el = s(id); return el ? (parseInt(el.value, 10) || 0) : fallback; };
    const getCheck = (id, fallback) => { const el = s(id); return el ? el.checked : fallback; };

    const collected = {
      fontFamily: getVal("font-family-select", this.state.style.fontFamily),
      fontSize: getInt("font-size-slider", this.state.style.fontSize),
      letterSpacing: getInt("letter-spacing-slider", this.state.style.letterSpacing),
      bold: getCheck("bold-toggle", this.state.style.bold),
      baseColor: getVal("base-color-input", this.state.style.baseColor),
      baseOutlineColor: getVal("base-outline-color-input", this.state.style.baseOutlineColor),
      outlineWidth: getInt("outline-width-slider", this.state.style.outlineWidth),
      shadowWidth: getInt("shadow-width-slider", this.state.style.shadowWidth),
      maleWipeColor: getVal("male-wipe-color", this.state.style.maleWipeColor),
      maleOutlineColor: getVal("male-outline-color", this.state.style.maleOutlineColor),
      femaleWipeColor: getVal("female-wipe-color", this.state.style.femaleWipeColor),
      femaleOutlineColor: getVal("female-outline-color", this.state.style.femaleOutlineColor),
      duetWipeColor: getVal("duet-wipe-color", this.state.style.duetWipeColor),
      duetOutlineColor: getVal("duet-outline-color", this.state.style.duetOutlineColor),
      defaultSinger: getVal("default-singer-select", this.state.style.defaultSinger),
      line1X: (getInt("line1-x-slider", Math.round(this.state.style.line1X * 100))) / 100,
      line1Y: (getInt("line1-y-slider", Math.round(this.state.style.line1Y * 100))) / 100,
      line2X: (getInt("line2-x-slider", Math.round(this.state.style.line2X * 100))) / 100,
      line2Y: (getInt("line2-y-slider", Math.round(this.state.style.line2Y * 100))) / 100,
      enableFade: getCheck("fade-toggle", this.state.style.enableFade !== false),
      fadeDuration: Math.round(getInt("fade-duration-slider", Math.round((this.state.style.fadeDuration || 0.4) * 10))) / 10,
      enableCountdown: getCheck("countdown-toggle", !!this.state.style.enableCountdown),
      bpm: getInt("song-bpm-slider", this.state.style.bpm || 80),
      countdownDotCount: getInt("countdown-dot-count", this.state.style.countdownDotCount || 4),
      countdownDotSize: getInt("countdown-dot-size", this.state.style.countdownDotSize || 22),
      countdownOffsetY: getInt("countdown-offset-y", this.state.style.countdownOffsetY || -46),
      countdownOffsetX: getInt("countdown-offset-x", this.state.style.countdownOffsetX || 10),
      showFadedGhost: getCheck("show-ghost-toggle", this.state.style.showFadedGhost !== false),
      maleDotFill: getVal("male-dot-fill", this.state.style.maleDotFill),
      maleDotOutline: getVal("male-dot-outline", this.state.style.maleDotOutline),
      maleDotOutlineWidth: getInt("male-dot-outline-width", this.state.style.maleDotOutlineWidth || 3),
      femaleDotFill: getVal("female-dot-fill", this.state.style.femaleDotFill),
      femaleDotOutline: getVal("female-dot-outline", this.state.style.femaleDotOutline),
      femaleDotOutlineWidth: getInt("female-dot-outline-width", this.state.style.femaleDotOutlineWidth || 3),
      duetDotFill: getVal("duet-dot-fill", this.state.style.duetDotFill),
      duetDotOutline: getVal("duet-dot-outline", this.state.style.duetDotOutline),
      duetDotOutlineWidth: getInt("duet-dot-outline-width", this.state.style.duetDotOutlineWidth || 3),
    };

    Object.assign(this.state.style, collected);
  }
}

window.StyleEditor = StyleEditor;
