// dwg-counting frontend
(() => {
  const $ = (id) => document.getElementById(id);
  const sections = {
    upload: $("s-upload"),
    processing: $("s-processing"),
    symbols: $("s-symbols"),
    results: $("s-results"),
  };
  const show = (name) => {
    for (const [k, el] of Object.entries(sections)) el.classList.toggle("hidden", k !== name);
  };

  let state = { jobId: null, symbols: [], selected: new Set(), results: [] };

  // Upload handlers
  const fileInput = $("file-input");
  const dropZone = $("drop-zone");
  $("browse-btn").addEventListener("click", () => fileInput.click());
  fileInput.addEventListener("change", (e) => e.target.files[0] && upload(e.target.files[0]));
  ["dragenter", "dragover"].forEach((ev) =>
    dropZone.addEventListener(ev, (e) => { e.preventDefault(); dropZone.classList.add("drag-over"); }));
  ["dragleave", "drop"].forEach((ev) =>
    dropZone.addEventListener(ev, (e) => { e.preventDefault(); dropZone.classList.remove("drag-over"); }));
  dropZone.addEventListener("drop", (e) => e.dataTransfer.files[0] && upload(e.dataTransfer.files[0]));

  async function upload(file) {
    show("processing");
    $("processing-title").textContent = "Připravuji výkres…";
    const fd = new FormData();
    fd.append("file", file);
    try {
      // Skip auto-detection by default — user defines symbols manually
      const r = await fetch("/api/upload?auto_detect=false", {
        method: "POST", body: fd,
      });
      if (!r.ok) throw new Error((await r.json()).detail || r.statusText);
      const data = await r.json();
      state.jobId = data.job_id;
      state.symbols = data.symbols || [];
      state.selected = new Set();
      renderSymbols();
      show("symbols");
    } catch (err) {
      alert("Chyba: " + err.message);
      show("upload");
    }
  }

  $("auto-detect-btn").addEventListener("click", async () => {
    if (!state.jobId) return;
    show("processing");
    $("processing-title").textContent = "Hledám legendu pomocí AI…";
    try {
      const r = await fetch(`/api/auto-detect/${state.jobId}`, { method: "POST" });
      if (!r.ok) throw new Error((await r.json()).detail || r.statusText);
      const data = await r.json();
      state.symbols = data.symbols || [];
      renderSymbols();
      show("symbols");
    } catch (err) {
      alert("Chyba: " + err.message);
      show("symbols");
    }
  });

  $("add-symbol-btn").addEventListener("click", () => {
    openAddSymbolModal();
  });

  $("upload-symbol-btn").addEventListener("click", () => {
    $("symbol-file-input").click();
  });
  $("symbol-file-input").addEventListener("change", async (e) => {
    const f = e.target.files[0];
    if (!f) return;
    const name = prompt("Název symbolu:", f.name.replace(/\.[a-z]+$/i, ""));
    if (!name) return;
    const fd = new FormData();
    fd.append("file", f);
    fd.append("description", name);
    try {
      const r = await fetch(`/api/symbols/${state.jobId}/upload`, { method: "POST", body: fd });
      if (!r.ok) throw new Error((await r.json()).detail || r.statusText);
      const sym = await r.json();
      state.symbols.push(sym);
      renderSymbols();
    } catch (err) { alert("Chyba: " + err.message); }
    e.target.value = "";
  });

  function renderSymbols() {
    const meta = $("symbols-meta");
    if (!state.symbols.length) {
      meta.textContent = 'Klikněte „+ Přidat symbol" a vyznačte ve výkresu, co chcete počítat. Nebo zkuste „Auto-detekce z legendy" pro automatický návrh.';
      $("symbols-grid").innerHTML = "";
      return;
    }
    meta.textContent = `${state.symbols.length} symbolů. Zaškrtněte k spočítání, ✎ upravit, 🗑 smazat.`;
    const grid = $("symbols-grid");
    grid.innerHTML = "";
    for (const s of state.symbols) {
      const card = document.createElement("div");
      card.className = "symbol-card";
      card.innerHTML = `
        <input type="checkbox" data-id="${s.id}">
        <img class="symbol-thumb" src="/api/symbol/${state.jobId}/${s.id}?v=${s._v||0}" alt=""
             onerror="this.style.visibility='hidden'">
        <div class="symbol-info">
          <div class="symbol-id">${s.id}</div>
          <div class="symbol-desc">${escapeHtml(s.description || "")}</div>
        </div>
        <button class="symbol-edit" type="button" title="Upravit výřez">✎</button>
        <button class="symbol-debug" type="button" title="Debug: zobrazit šablonu a skóre">🔍</button>
        <button class="symbol-delete" type="button" title="Smazat symbol">🗑</button>`;
      const cb = card.querySelector("input");
      cb.addEventListener("change", () => {
        if (cb.checked) { state.selected.add(s.id); card.classList.add("selected"); }
        else { state.selected.delete(s.id); card.classList.remove("selected"); }
        $("count-btn").disabled = state.selected.size === 0;
      });
      // Click on row toggles checkbox (except on edit btn / thumb)
      card.addEventListener("click", (e) => {
        if (e.target.closest(".symbol-edit") || e.target === cb) return;
        cb.checked = !cb.checked;
        cb.dispatchEvent(new Event("change"));
      });
      card.querySelector(".symbol-edit").addEventListener("click", (e) => {
        e.stopPropagation();
        openCropModal(s);
      });
      card.querySelector(".symbol-debug").addEventListener("click", (e) => {
        e.stopPropagation();
        openDebugModal(s);
      });
      card.querySelector(".symbol-delete").addEventListener("click", async (e) => {
        e.stopPropagation();
        if (!confirm(`Smazat symbol "${s.description || s.id}"?`)) return;
        try {
          const r = await fetch(`/api/symbols/${state.jobId}/${s.id}`, { method: "DELETE" });
          if (!r.ok) throw new Error("delete failed");
          state.symbols = state.symbols.filter(x => x.id !== s.id);
          state.selected.delete(s.id);
          renderSymbols();
          $("count-btn").disabled = state.selected.size === 0;
        } catch (err) { alert("Chyba: " + err.message); }
      });
      grid.appendChild(card);
    }
  }

  // Add-new-symbol modal: same crop modal, but uses full drawing image and
  // asks for a name.
  function openAddSymbolModal() {
    const modal = $("crop-modal");
    const img = $("crop-img");
    const sel = $("crop-selection");
    const wrap = $("crop-canvas-wrap");
    $("crop-modal-title").textContent = "Nový symbol — vyznačte oblast ve výkresu";
    $("crop-modal-hint").textContent =
      "DOPORUČENO: najděte symbol PŘÍMO ve výkresu (ne v legendě) — barvy a tloušťka čar tam přesně odpovídají tomu, co budeme hledat. Vyznačte těsný rámeček kolem jedné instance symbolu a pojmenujte ho.";
    $("crop-name-row").classList.remove("hidden");
    $("crop-name").value = "";
    img.src = `/api/drawing/${state.jobId}`;
    sel.style.display = "none";
    $("crop-save").disabled = true;
    cropState = { mode: "create", sym: null, bbox: null, dragging: false };
    modal.classList.remove("hidden");
    attachCropHandlers(wrap, img, sel);
  }

  // ── Crop modal logic ──────────────────────
  let cropState = null;

  function openCropModal(sym) {
    const modal = $("crop-modal");
    const img = $("crop-img");
    const sel = $("crop-selection");
    const wrap = $("crop-canvas-wrap");
    $("crop-modal-title").textContent = `Upravit symbol: ${sym.description || sym.id}`;
    $("crop-modal-hint").textContent =
      "Označte oblast obsahující pouze grafický symbol (bez popisu).";
    $("crop-name-row").classList.add("hidden");
    // For editing: use the full drawing so user can pick any instance
    img.src = `/api/drawing/${state.jobId}`;
    sel.style.display = "none";
    $("crop-save").disabled = true;
    cropState = { mode: "edit", sym, bbox: null, dragging: false };
    modal.classList.remove("hidden");
    attachCropHandlers(wrap, img, sel);
    return;
  }

  function attachCropHandlers(wrap, img, sel) {

    // Mouse coords relative to the IMAGE's top-left (in image-pixel space,
    // which is also wrap's content space since image is at native scale and
    // sits at content origin (0,0) in the relative-positioned wrap).
    function localXY(e) {
      const rect = img.getBoundingClientRect();
      return { x: e.clientX - rect.left, y: e.clientY - rect.top };
    }

    function onMouseDown(e) {
      const p = localXY(e);
      cropState.startX = p.x;
      cropState.startY = p.y;
      cropState.dragging = true;
      sel.style.display = "block";
      sel.style.left = p.x + "px";
      sel.style.top = p.y + "px";
      sel.style.width = "0px";
      sel.style.height = "0px";
    }
    function onMouseMove(e) {
      if (!cropState || !cropState.dragging) return;
      const p = localXY(e);
      const left = Math.min(p.x, cropState.startX);
      const top = Math.min(p.y, cropState.startY);
      const w = Math.abs(p.x - cropState.startX);
      const h = Math.abs(p.y - cropState.startY);
      sel.style.left = left + "px";
      sel.style.top = top + "px";
      sel.style.width = w + "px";
      sel.style.height = h + "px";
    }
    function onMouseUp() {
      if (!cropState) return;
      cropState.dragging = false;
      const rect = img.getBoundingClientRect();
      const dispW = rect.width, dispH = rect.height;
      const left = parseFloat(sel.style.left), top = parseFloat(sel.style.top);
      const w = parseFloat(sel.style.width), h = parseFloat(sel.style.height);
      if (w < 5 || h < 5) {
        sel.style.display = "none";
        $("crop-save").disabled = true;
        return;
      }
      cropState.bbox = {
        x: left / dispW,
        y: top / dispH,
        w: w / dispW,
        h: h / dispH,
      };
      $("crop-save").disabled = false;
    }

    wrap.onmousedown = onMouseDown;
    wrap.onmousemove = onMouseMove;
    wrap.onmouseup = onMouseUp;
    wrap.onmouseleave = onMouseUp;
  }

  function closeCropModal() {
    $("crop-modal").classList.add("hidden");
    cropState = null;
  }

  async function openDebugModal(sym) {
    const modal = $("debug-modal");
    const body = $("debug-body");
    $("debug-title").textContent = `Debug: ${sym.description || sym.id}`;
    body.innerHTML = '<p style="padding:20px">Načítám diagnostiku…</p>';
    modal.classList.remove("hidden");
    try {
      const r = await fetch(`/api/debug/${state.jobId}/${sym.id}`);
      if (!r.ok) throw new Error(await r.text());
      const info = await r.json();
      const tmplURL = `/api/symbol/${state.jobId}/${sym.id}?v=${sym._v||0}`;
      const procURL = `/api/debug-template/${state.jobId}/${sym.id}?v=${sym._v||0}&t=${Date.now()}`;
      const drawURL = `/api/drawing/${state.jobId}`;
      const matches = info.matches_at_threshold || {};
      const maxMatchCount = Math.max(1, ...Object.values(matches));
      const threshRows = Object.entries(matches).map(([t, n]) => `
        <div>práh ${t}</div>
        <div class="debug-bar"><div class="debug-bar-fill" style="width:${Math.min(100,(n/maxMatchCount)*100)}%"></div></div>
        <div>${n} shod</div>`).join("");
      const inkPct = info.template_total_pixels
        ? ((info.template_ink_pixels / info.template_total_pixels) * 100).toFixed(1)
        : "?";
      body.innerHTML = `
        <div class="debug-section">
          <h4>Obrazy</h4>
          <div class="debug-thumbs">
            <div class="debug-thumb">
              <a href="${tmplURL}" target="_blank"><img src="${tmplURL}" alt=""></a>
              <span>Šablona (uložená)</span>
            </div>
            <div class="debug-thumb">
              <a href="${procURL}" target="_blank"><img src="${procURL}" alt=""></a>
              <span>Po předzpracování<br>(co matcher vidí)</span>
            </div>
            <div class="debug-thumb">
              <a href="${drawURL}" target="_blank">otevřít celý výkres ↗</a>
              <span>${info.drawing_size.join(" × ")} px</span>
            </div>
          </div>
        </div>
        <div class="debug-section">
          <h4>Měření</h4>
          <div class="debug-kv">
            <strong>Šablona originál</strong><span>${info.template_size.join(" × ")} px</span>
            <strong>Šablona po ořezu</strong><span>${info.template_cropped_size.join(" × ")} px</span>
            <strong>Inkoust v šabloně</strong><span>${info.template_ink_pixels} / ${info.template_total_pixels} px (${inkPct}%)</span>
            <strong>Výkres</strong><span>${info.drawing_size.join(" × ")} px</span>
            <strong>Nejlepší skóre</strong><span>${info.max_score?.toFixed(3) ?? "—"}</span>
          </div>
        </div>
        <div class="debug-section">
          <h4>Shody při různých prazích (bez rotací, scale 1.0)</h4>
          <div class="debug-thresholds">${threshRows}</div>
          <p style="margin-top:8px; color: var(--text-tertiary); font-size:12px">
            Aktuálně používaný práh pro počítání: <strong>0.75</strong>.
            Skutečné počty (s rotacemi 0/90/180/270° a třemi scale faktory) jsou typicky nižší kvůli dedupli­kaci.
          </p>
        </div>
        <div class="debug-section" id="debug-interpret"></div>
      `;
      // Heuristic interpretation
      const interpret = [];
      if (info.template_ink_pixels < 30)
        interpret.push('⚠ Šablona obsahuje příliš málo „inkoustu" — pravděpodobně jste vybrali převážně bílou plochu. Vyznačte rámeček těsně kolem čar symbolu.');
      if (Math.min(...info.template_cropped_size) < 12)
        interpret.push("⚠ Šablona je velmi malá (<12 px). Malé šablony hlásí spoustu falešných shod nebo žádné. Zkuste přidat trochu okolí.");
      if ((info.max_score ?? 0) < 0.5)
        interpret.push("⚠ Nejlepší skóre v celém výkresu je velmi nízké — symbol vypadá v plánu jinak než v šabloně. Zkuste vyznačit symbol přímo z plánu (ne z legendy), nebo zkuste jinou variantu/orientaci.");
      else if ((info.max_score ?? 0) < 0.7)
        interpret.push("ℹ Nejlepší skóre ≈ " + info.max_score.toFixed(2) + ". Práh 0.75 je nad maximem — zkuste snížit práh nebo upravit šablonu těsněji.");
      else
        interpret.push("✓ Symbol se v plánu vyskytuje. Pokud nejsou shody, může jít o problém s rotacemi nebo měřítkem.");
      $("debug-interpret").innerHTML = "<h4>Interpretace</h4>" +
        interpret.map(t => `<p>${t}</p>`).join("");
    } catch (err) {
      body.innerHTML = `<p style="color:#dc2626; padding:12px">Chyba: ${err.message}</p>`;
    }
  }

  $("debug-close").addEventListener("click", () => $("debug-modal").classList.add("hidden"));
  $("debug-ok").addEventListener("click", () => $("debug-modal").classList.add("hidden"));

  $("crop-close").addEventListener("click", closeCropModal);
  $("crop-cancel").addEventListener("click", closeCropModal);
  $("crop-save").addEventListener("click", async () => {
    if (!cropState || !cropState.bbox) return;
    try {
      if (cropState.mode === "create") {
        const name = ($("crop-name").value || "").trim();
        if (!name) { alert("Zadejte název symbolu."); return; }
        const r = await fetch(`/api/symbols/${state.jobId}`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({
            bbox: cropState.bbox,
            description: name,
            source: "drawing",
          }),
        });
        if (!r.ok) throw new Error((await r.json()).detail || r.statusText);
        const newSym = await r.json();
        state.symbols.push(newSym);
      } else {
        const r = await fetch(`/api/symbol/${state.jobId}/${cropState.sym.id}/recrop`, {
          method: "POST",
          headers: { "Content-Type": "application/json" },
          body: JSON.stringify({ bbox: cropState.bbox }),
        });
        if (!r.ok) throw new Error((await r.json()).detail || r.statusText);
        cropState.sym._v = (cropState.sym._v || 0) + 1;
      }
      renderSymbols();
      closeCropModal();
    } catch (err) {
      alert("Chyba: " + err.message);
    }
  });

  // Threshold slider live readout
  const thrSlider = $("threshold-slider");
  const thrValue = $("threshold-value");
  thrSlider.addEventListener("input", () => {
    thrValue.textContent = parseFloat(thrSlider.value).toFixed(2);
  });

  $("count-btn").addEventListener("click", async () => {
    show("processing");
    $("processing-title").textContent = `Počítám ${state.selected.size} symbolů…`;
    try {
      const r = await fetch(`/api/count/${state.jobId}`, {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          symbol_ids: [...state.selected],
          threshold: parseFloat(thrSlider.value),
        }),
      });
      if (!r.ok) throw new Error((await r.json()).detail || r.statusText);
      const data = await r.json();
      state.results = data.results || [];
      renderResults();
      show("results");
    } catch (err) {
      alert("Chyba: " + err.message);
      show("symbols");
    }
  });

  function renderResults() {
    const total = state.results.reduce((a, r) => a + (r.count || 0), 0);
    $("results-meta").textContent = `Celkem ${total} symbolů ve ${state.results.length} kategoriích.`;
    const tb = $("results-tbody");
    tb.innerHTML = "";
    for (const r of state.results) {
      const tr = document.createElement("tr");
      const conf = r.confidence || "";
      tr.innerHTML = `
        <td><img class="symbol-thumb" style="width:40px;height:40px" src="/api/symbol/${state.jobId}/${r.id}" alt=""></td>
        <td>${escapeHtml(r.description || "")}</td>
        <td><strong>${r.count}</strong></td>
        <td class="confidence-${conf}">${conf || "—"}</td>
        <td>${escapeHtml(r.notes || "")}</td>`;
      tb.appendChild(tr);
    }
  }

  $("export-btn").addEventListener("click", () => {
    window.location.href = `/api/export/${state.jobId}`;
  });
  $("pdf-btn").addEventListener("click", () => {
    window.location.href = `/api/export-pdf/${state.jobId}`;
  });

  $("back-btn").addEventListener("click", () => show("symbols"));
  $("reset-btn").addEventListener("click", () => {
    state = { jobId: null, symbols: [], selected: new Set(), results: [] };
    fileInput.value = "";
    show("upload");
  });

  function escapeHtml(s) {
    return String(s).replace(/[&<>"']/g, (c) => ({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"}[c]));
  }
})();
