(function ($) {
  "use strict";

  let selectedFiles = [];
  let dragFileId = null;
  let currentJobId = null;
  let pollTimer = null;
  let pollingJobId = null;

  const $dropZone = $("#dropZone");
  const $fileInput = $("#pdfFile");
  const $fileList = $("#fileList");
  const $fileSummary = $("#fileSummary");
  const $btnProcess = $("#btnProcess");
  const $progressCard = $("#progressCard");
  const $progressBar = $("#progressBar");
  const $progressPct = $("#progressPct");
  const $progressMsg = $("#progressMsg");
  const $progressLabel = $("#progressLabel");
  const $resultBody = $("#resultBody");
  const $emptyRow = $("#emptyRow");
  const $resultActions = $("#resultActions");
  const $resultSummary = $("#resultSummary");
  const $resultTitle = $("#resultTitle");
  const $historyList = $("#historyList");
  const $historyEmpty = $("#historyEmpty");
  const $historyCount = $("#historyCount");
  const $docProfile = $("#docProfile");
  const $prefix = $("#prefix");
  const $btnCancelJob = $("#btnCancelJob");
  const $btnEditSegments = $("#btnEditSegments");
  let editModal = null;
  let editPageCount = 0;
  let docProfiles = [];
  let currentJobStatus = null;
  let licenseStatus = null;
  let licenseModal = null;
  let aboutModal = null;
  let aboutInfo = null;

  const $licenseBanner = $("#licenseBanner");
  const $licenseBannerText = $("#licenseBannerText");
  const $licenseFooter = $("#licenseFooter");
  const $machineIdField = $("#machineIdField");
  const $licenseKeyField = $("#licenseKeyField");
  const $licenseModalStatus = $("#licenseModalStatus");

  function openLicenseModal() {
    if (!licenseModal) {
      licenseModal = new bootstrap.Modal(document.getElementById("licenseModal"));
    }
    if (licenseStatus) {
      $machineIdField.val(licenseStatus.machine_id || "");
      $licenseModalStatus.text(licenseStatus.message || "");
    }
    licenseModal.show();
  }

  function formatLicenseDetail(st) {
    if (!st) return "—";
    if (st.mode === "licensed") {
      let line = st.holder || "Đã kích hoạt";
      if (st.license_perpetual) {
        line += " · Vĩnh viễn";
      } else if (st.license_expires_display) {
        line += " · Hết hạn " + st.license_expires_display;
        if (st.license_days_left != null) {
          line += " (còn " + st.license_days_left + " ngày)";
        }
      }
      return line;
    }
    if (st.mode === "trial") {
      return "Dùng thử · còn " + (st.trial_days_left != null ? st.trial_days_left : "?")
        + " ngày · xử lý " + (st.max_pages != null ? st.max_pages : 10) + " trang đầu/PDF";
    }
    return st.message || st.mode;
  }

  function fillAbout(data) {
    aboutInfo = data;
    $("#aboutAppName").text(data.name || "PDFEX");
    $("#aboutTagline").text(data.tagline || "");
    $("#aboutVersion").text("v" + (data.version || "?"));
    $("#aboutCopyright").text(data.copyright || "");
    $("#aboutEula").text(data.eula_short || "");
    const lic = data.license || licenseStatus;
    $("#aboutLicenseDetail").text(formatLicenseDetail(lic));
    $("#navTagline").text((data.tagline || "") + " v" + (data.version || "").split(".")[0]);

    const pay = data.payment || {};
    const memo = pay.transfer_memo || (lic && lic.machine_id) || "";
    $("#aboutTransferMemo").val(memo);

    const $onlineSteps = $("#aboutOnlineSteps");
    $onlineSteps.empty();
    (pay.online_steps || []).forEach(function (step) {
      $onlineSteps.append($("<li>").text(step));
    });
    if (pay.online_url) {
      $("#aboutPayShopLink").attr("href", pay.online_url);
    }
    $("#aboutOnlineNote").text(pay.online_note || "");

    if (pay.qr_url) {
      const sep = pay.qr_url.indexOf("?") >= 0 ? "&" : "?";
      $("#aboutPaymentQr").attr("src", pay.qr_url + sep + "t=" + Date.now());
    }
    const $steps = $("#aboutPaymentSteps");
    $steps.empty();
    const manualSteps = pay.manual_steps || pay.steps || [];
    manualSteps.forEach(function (step) {
      $steps.append($("<li>").text(step));
    });
    const zalo = pay.zalo || "0989629779";
    $("#aboutZaloPhone").text(zalo);
    $("#aboutZaloLink").attr("href", pay.zalo_url || ("https://zalo.me/" + zalo));
    $("#aboutPaymentNote").text(pay.note || "");
  }

  function openAboutModal() {
    if (!aboutModal) {
      aboutModal = new bootstrap.Modal(document.getElementById("aboutModal"));
    }
    $.getJSON("/api/about")
      .done(function (data) {
        fillAbout(data);
        aboutModal.show();
      })
      .fail(function () {
        if (aboutInfo) {
          fillAbout(aboutInfo);
          aboutModal.show();
          return;
        }
        Swal.fire({ icon: "error", title: "Không tải được thông tin ứng dụng" });
      });
  }

  const LICENSE_EXPIRY_WARN_DAYS = 3;

  function applyLicenseUI(st) {
    licenseStatus = st;
    $licenseFooter.text(st.message || "—");
    $machineIdField.val(st.machine_id || "");

    if (st.mode === "licensed") {
      $licenseBanner.removeClass("alert-warning alert-danger alert-success");
      if (
        !st.license_perpetual
        && st.license_days_left != null
        && st.license_days_left < LICENSE_EXPIRY_WARN_DAYS
      ) {
        $licenseBanner.removeClass("d-none").addClass("alert-warning");
        $licenseBannerText.text(
          "License hết hạn sau " + st.license_days_left + " ngày ("
          + (st.license_expires_display || "") + ")"
        );
      } else {
        $licenseBanner.addClass("d-none");
      }
      $btnProcess.prop("disabled", !selectedFiles.length);
      if (aboutInfo) {
        aboutInfo.license = st;
      }
      return;
    }

    $licenseBanner.removeClass("d-none alert-success alert-danger alert-warning");
    if (st.mode === "expired" || st.mode === "invalid") {
      $licenseBanner.addClass("alert-danger");
      $licenseBannerText.text(st.message || "Cần kích hoạt license.");
      if (!selectedFiles.length || st.mode === "expired" || st.mode === "invalid") {
        $btnProcess.prop("disabled", st.mode !== "trial" || !selectedFiles.length);
      }
      if (st.mode === "expired" || st.mode === "invalid") {
        $btnProcess.prop("disabled", true);
      }
    } else {
      $licenseBanner.addClass("alert-warning");
      const days = st.trial_days_left != null ? st.trial_days_left : "?";
      const pages = st.max_pages != null ? st.max_pages : 10;
      $licenseBannerText.text("Dùng thử — còn " + days + " ngày · xử lý " + pages + " trang đầu/PDF");
      $btnProcess.prop("disabled", !selectedFiles.length);
    }
  }

  function loadLicenseStatus() {
    $.getJSON("/api/license/status")
      .done(function (st) {
        applyLicenseUI(st);
        if (st.mode === "expired" || st.mode === "invalid") {
          setTimeout(openLicenseModal, 600);
        }
      })
      .fail(function () {
        console.warn("Không tải được trạng thái license");
      });
  }

  function submitActivation() {
    const key = ($licenseKeyField.val() || "").trim();
    if (!key) {
      Swal.fire({ icon: "warning", title: "Nhập license key" });
      return;
    }
    $.ajax({
      url: "/api/license/activate",
      type: "POST",
      contentType: "application/json",
      data: JSON.stringify({ key: key }),
    })
      .done(function (res) {
        if (res.status) {
          applyLicenseUI(res.status);
        }
        $licenseKeyField.val("");
        if (licenseModal) {
          licenseModal.hide();
        }
        Swal.fire({
          icon: "success",
          title: "Kích hoạt thành công",
          text: res.status && res.status.holder ? res.status.holder : "",
          timer: 2500,
          showConfirmButton: false,
        });
      })
      .fail(function (xhr) {
        const msg = xhr.responseJSON && xhr.responseJSON.detail
          ? xhr.responseJSON.detail : "Kích hoạt thất bại";
        Swal.fire({ icon: "error", title: "Không kích hoạt được", text: msg });
      });
  }

  $("#btnActivateLink, #btnLicenseInfo").on("click", function (e) {
    e.preventDefault();
    openLicenseModal();
  });

  $("#btnAbout").on("click", function (e) {
    e.preventDefault();
    openAboutModal();
  });

  $("#btnAboutActivate").on("click", function () {
    if (aboutModal) {
      aboutModal.hide();
    }
    openLicenseModal();
  });

  $("#btnCopyTransferMemo").on("click", function () {
    const val = $("#aboutTransferMemo").val();
    if (!val) return;
    navigator.clipboard.writeText(val).then(function () {
      Swal.fire({ icon: "success", title: "Đã sao chép nội dung CK", timer: 1500, showConfirmButton: false });
    }).catch(function () {
      $("#aboutTransferMemo").trigger("select");
      document.execCommand("copy");
      Swal.fire({ icon: "success", title: "Đã sao chép nội dung CK", timer: 1500, showConfirmButton: false });
    });
  });

  $("#aboutPaymentQr").on("click", function () {
    const src = $(this).attr("src");
    if (!src) return;
    Swal.fire({
      title: "Quét mã chuyển khoản",
      html: '<img src="' + src + '" alt="QR" style="max-width:220px;width:100%;">'
        + '<p class="small text-muted mt-2 mb-0">Nội dung CK: <strong>' + $("#aboutTransferMemo").val() + "</strong></p>",
      confirmButtonText: "Đóng",
    });
  });

  $("#btnActivateSubmit").on("click", submitActivation);

  $("#btnCopyMachineId").on("click", function () {
    const val = $machineIdField.val();
    if (!val) return;
    navigator.clipboard.writeText(val).then(function () {
      Swal.fire({ icon: "success", title: "Đã sao chép mã máy", timer: 1500, showConfirmButton: false });
    }).catch(function () {
      $machineIdField.trigger("select");
      document.execCommand("copy");
      Swal.fire({ icon: "success", title: "Đã sao chép mã máy", timer: 1500, showConfirmButton: false });
    });
  });

  function applyProfilePrefix(profileId) {
    const p = docProfiles.find(function (x) { return x.id === profileId; });
    if (p && p.default_prefix) {
      $prefix.val(p.default_prefix);
    }
  }

  function loadDocProfiles() {
    $.getJSON("/api/doc-profiles")
      .done(function (items) {
        docProfiles = items || [];
        $docProfile.empty();
        docProfiles.forEach(function (p) {
          $docProfile.append(
            $("<option>").val(p.id).text(p.label)
          );
        });
        applyProfilePrefix($docProfile.val() || "auto");
      })
      .fail(function () {
        console.warn("Không tải được danh sách loại văn bản");
      });
  }

  $docProfile.on("change", function () {
    applyProfilePrefix($(this).val());
  });

  function formatDate(iso) {
    if (!iso) return "—";
    const d = new Date(iso);
    if (isNaN(d)) return iso;
    const pad = (n) => String(n).padStart(2, "0");
    return pad(d.getDate()) + "/" + pad(d.getMonth() + 1) + "/" + d.getFullYear()
      + " " + pad(d.getHours()) + ":" + pad(d.getMinutes());
  }

  function formatNgayBanHanh(val) {
    if (!val) return "";
    const m = String(val).match(/^(\d{1,2})[-\/](\d{1,2})[-\/](\d{4})$/);
    if (m) {
      return String(m[1]).padStart(2, "0") + "/"
        + String(m[2]).padStart(2, "0") + "/" + m[3];
    }
    return String(val);
  }

  function copyToClipboard(text) {
    if (!text) return Promise.reject(new Error("empty"));
    if (navigator.clipboard && navigator.clipboard.writeText) {
      return navigator.clipboard.writeText(text);
    }
    return new Promise(function (resolve, reject) {
      const ta = document.createElement("textarea");
      ta.value = text;
      ta.style.position = "fixed";
      ta.style.left = "-9999px";
      document.body.appendChild(ta);
      ta.select();
      try {
        document.execCommand("copy") ? resolve() : reject(new Error("copy failed"));
      } catch (err) {
        reject(err);
      }
      document.body.removeChild(ta);
    });
  }

  function appendCopyCell(tr, copyText, displayText, textClass) {
    const text = copyText == null ? "" : String(copyText);
    const show = displayText != null ? String(displayText) : text;
    const $wrap = $("<div>").addClass("cell-with-copy");
    const $span = $("<span>").addClass("cell-text" + (textClass ? " " + textClass : ""))
      .attr("title", text).text(show);
    $wrap.append($span);
    if (text) {
      $wrap.append(
        $("<button type='button'>")
          .addClass("btn btn-copy-cell")
          .attr("title", "Sao chép")
          .attr("data-copy", text)
          .html('<i class="bi bi-clipboard"></i>')
      );
    }
    tr.append($("<td>").append($wrap));
  }

  $("#resultTable").on("click", ".btn-copy-cell", function (e) {
    e.preventDefault();
    e.stopPropagation();
    const text = $(this).attr("data-copy") || "";
    if (!text) return;
    const $btn = $(this);
    copyToClipboard(text).then(function () {
      $btn.addClass("copied").find("i").removeClass("bi-clipboard").addClass("bi-check-lg");
      setTimeout(function () {
        $btn.removeClass("copied").find("i").removeClass("bi-check-lg").addClass("bi-clipboard");
      }, 1200);
    }).catch(function () {
      Swal.fire({ icon: "error", title: "Không sao chép được", timer: 1500, showConfirmButton: false });
    });
  });

  function statusBadge(status) {
    const map = {
      completed: '<span class="badge bg-success">Xong</span>',
      running: '<span class="badge bg-primary">Đang chạy</span>',
      queued: '<span class="badge bg-secondary">Chờ</span>',
      failed: '<span class="badge bg-danger">Lỗi</span>',
      cancelled: '<span class="badge bg-warning text-dark">Đã hủy</span>',
    };
    return map[status] || status;
  }

  function updateJobActions(job) {
    if (!job || !currentJobId) {
      $resultActions.hide();
      $btnCancelJob.hide();
      return;
    }
    currentJobStatus = job.status;
    const isRunning = job.status === "running" || job.status === "queued";
    const isDone = job.status === "completed";

    $btnCancelJob.toggle(isRunning);
    $resultActions.show();
    $("#btnDownload").toggle(isDone);
    $("#btnOpenFolder").toggle(isDone);
    $btnEditSegments.toggle(isDone);
    $("#btnMineMarkers").toggle(isDone);
    $("#btnDeleteJob").show();
  }

  function buildTypeSelect(currentLabel) {
    const $sel = $('<select class="form-select form-select-sm edit-type">');
    $sel.append($("<option>").val("").text("— tự động —"));
    const seen = {};
    (docProfiles || []).forEach(function (p) {
      if (p.id === "auto" || !p.label || seen[p.label]) return;
      seen[p.label] = true;
      $sel.append($("<option>").val(p.label).text(p.label));
    });
    if (currentLabel && !seen[currentLabel]) {
      $sel.append($("<option>").val(currentLabel).text(currentLabel));
    }
    $sel.val(currentLabel || "");
    return $sel;
  }

  function renderEditRow(page) {
    const $tr = $('<tr class="edit-row">').attr("data-index", page.index);
    $tr.append($("<td>").addClass("text-center fw-semibold").text(page.index + 1));

    const isFirst = page.index === 0;
    const $chk = $('<input type="checkbox" class="form-check-input edit-start">')
      .prop("checked", page.is_start || isFirst);
    if (isFirst) {
      $chk.prop("disabled", true).prop("checked", true);
    }
    $tr.append($("<td>").addClass("text-center").append($chk));
    $tr.append($("<td>").addClass("small text-muted edit-snippet").attr("title", page.snippet).text(page.snippet || "(trang trống)"));

    const $typeCell = $("<td>").append(buildTypeSelect(page.doc_type));
    $tr.append($typeCell);
    return $tr;
  }

  function refreshEditTypeStates() {
    let docs = 0;
    $("#editPagesBody .edit-row").each(function () {
      const $row = $(this);
      const isStart = $row.find(".edit-start").prop("checked");
      $row.find(".edit-type").prop("disabled", !isStart);
      $row.toggleClass("table-active", isStart);
      if (isStart) docs += 1;
    });
    $("#editDocCount").text(docs + " văn bản / " + editPageCount + " trang");
  }

  function openEditModal() {
    if (!currentJobId) return;
    $.getJSON("/api/jobs/" + currentJobId + "/segments", { _: Date.now() })
      .done(function (data) {
        if (!data.editable) {
          Swal.fire({ icon: "info", title: "Chưa hỗ trợ sửa", text: data.reason || "" });
          return;
        }
        editPageCount = data.page_count;
        const $body = $("#editPagesBody").empty();
        (data.pages || []).forEach(function (p) {
          $body.append(renderEditRow(p));
        });
        refreshEditTypeStates();
        if (!editModal) {
          editModal = new bootstrap.Modal(document.getElementById("editModal"));
        }
        editModal.show();
      })
      .fail(function (xhr) {
        const msg = xhr.responseJSON && xhr.responseJSON.detail
          ? xhr.responseJSON.detail : "Không tải được dữ liệu trang";
        Swal.fire({ icon: "error", title: "Lỗi", text: msg });
      });
  }

  function collectBoundaries() {
    const starts = [];
    $("#editPagesBody .edit-row").each(function () {
      const $row = $(this);
      const idx = parseInt($row.attr("data-index"), 10);
      if ($row.find(".edit-start").prop("checked") || idx === 0) {
        starts.push({ index: idx, doc_type: ($row.find(".edit-type").val() || "").trim() });
      }
    });
    const boundaries = [];
    for (let i = 0; i < starts.length; i++) {
      const start = starts[i].index;
      const end = (i + 1 < starts.length ? starts[i + 1].index : editPageCount) - 1;
      boundaries.push({ start: start, end: end, doc_type: starts[i].doc_type || null });
    }
    return boundaries;
  }

  function saveSegments() {
    if (!currentJobId) return;
    const boundaries = collectBoundaries();
    const teach = $("#editTeach").prop("checked");
    const $btn = $("#btnSaveSegments").prop("disabled", true)
      .html('<span class="spinner-border spinner-border-sm"></span> Đang lưu...');

    $.ajax({
      url: "/api/jobs/" + currentJobId + "/segments",
      type: "POST",
      contentType: "application/json",
      data: JSON.stringify({ boundaries: boundaries, teach: teach }),
    })
      .done(function (res) {
        if (editModal) editModal.hide();
        if (currentJobId) loadJob(currentJobId, { startPoll: false });
        const learnMsg = res.learned ? (" · đã học " + res.learned + " mẫu") : "";
        const sugMsg = res.suggested ? (" · " + res.suggested + " gợi ý dấu hiệu vùng") : "";
        Swal.fire({
          icon: "success",
          title: "Đã lưu",
          html: res.doc_count + " văn bản" + learnMsg + sugMsg
            + (res.suggested ? '<br><span class="small text-muted">Mở <a href="/manage" target="_blank">Tri thức → Dấu hiệu vùng</a> để duyệt gợi ý.</span>' : ""),
          timer: res.suggested ? 4500 : 2500,
          showConfirmButton: !!res.suggested,
        });
      })
      .fail(function (xhr) {
        const msg = xhr.responseJSON && xhr.responseJSON.detail
          ? xhr.responseJSON.detail : "Lưu thất bại";
        Swal.fire({ icon: "error", title: "Lỗi", text: msg });
      })
      .always(function () {
        $btn.prop("disabled", false).html('<i class="bi bi-check-lg"></i> Lưu &amp; dạy');
      });
  }

  $("#editPagesBody").on("change", ".edit-start", refreshEditTypeStates);
  $btnEditSegments.on("click", openEditModal);
  $("#btnSaveSegments").on("click", saveSegments);

  function mineMarkers() {
    if (!currentJobId) return;
    const $btn = $("#btnMineMarkers");
    $btn.prop("disabled", true);
    fetch("/api/jobs/" + currentJobId + "/mine-markers", { method: "POST" })
      .then(function (r) { return r.json().then(function (j) { if (!r.ok) throw new Error(j.detail || "Lỗi"); return j; }); })
      .then(function (j) {
        const n = j.added || 0;
        Swal.fire({
          icon: n ? "success" : "info",
          title: n ? ("Đã thêm " + n + " gợi ý") : "Không có gợi ý mới",
          html: n
            ? 'Mở trang <a href="/manage" target="_blank">Tri thức → Dấu hiệu vùng</a> để duyệt và chấp nhận.'
            : "Các dấu hiệu vùng ở file này đã được nhận diện hoặc đã có sẵn.",
        });
      })
      .catch(function (e) { Swal.fire({ icon: "error", title: "Lỗi", text: e.message }); })
      .always(function () { $btn.prop("disabled", false); });
  }
  $("#btnMineMarkers").on("click", mineMarkers);

  function deleteCurrentJob() {
    if (!currentJobId) return;
    Swal.fire({
      icon: "warning",
      title: "Xóa công việc?",
      text: "File upload và kết quả (nếu có) sẽ bị xóa.",
      showCancelButton: true,
      confirmButtonText: "Xóa",
      cancelButtonText: "Không",
    }).then(function (result) {
      if (!result.isConfirmed) return;
      $.ajax({ url: "/api/jobs/" + currentJobId, type: "DELETE" })
        .done(function () {
          stopPolling();
          currentJobId = null;
          currentJobStatus = null;
          $btnProcess.prop("disabled", false);
          $resultBody.empty().append(
            $("<tr id='emptyRow'>").append(
              $("<td colspan='7' class='text-center text-muted py-5'>").html(
                '<i class="bi bi-inbox fs-2 d-block mb-2"></i>Chọn công việc từ lịch sử hoặc phân tích file mới.'
              )
            )
          );
          $resultActions.hide();
          $btnCancelJob.hide();
          $resultSummary.hide();
          $progressCard.hide();
          loadHistory();
        })
        .fail(function () {
          Swal.fire({ icon: "error", title: "Không xóa được công việc" });
        });
    });
  }

  function newFileId() {
    return "f_" + Date.now().toString(36) + "_" + Math.random().toString(36).slice(2, 8);
  }

  function isPdfFile(file) {
    return file && file.name && file.name.toLowerCase().endsWith(".pdf");
  }

  function updateProcessButton() {
    const canProcess = !licenseStatus
      || licenseStatus.mode === "trial"
      || licenseStatus.mode === "licensed";
    $btnProcess.prop("disabled", !canProcess || !selectedFiles.length);
  }

  function renderFileList() {
    $fileList.empty();
    if (!selectedFiles.length) {
      $fileList.addClass("d-none");
      $fileSummary.addClass("d-none").text("");
      $dropZone.removeClass("has-file");
      updateProcessButton();
      return;
    }

    $fileList.removeClass("d-none");
    $dropZone.addClass("has-file");
    $fileSummary.removeClass("d-none").text(
      selectedFiles.length === 1
        ? "1 file PDF"
        : selectedFiles.length + " file PDF — xử lý lần lượt, gộp kết quả"
    );

    selectedFiles.forEach(function (entry, index) {
      const $li = $("<li>")
        .addClass("file-queue-item")
        .attr("draggable", true)
        .attr("data-id", entry.id);

      $li.append('<span class="fq-handle" title="Kéo để sắp xếp"><i class="bi bi-grip-vertical"></i></span>');
      $li.append($("<span>").addClass("fq-index").text(index + 1));
      $li.append(
        $("<span>").addClass("fq-name").attr("title", entry.file.name).text(entry.file.name)
      );
      $li.append(
        $("<button type='button'>")
          .addClass("fq-remove")
          .attr("title", "Xóa")
          .html('<i class="bi bi-x-lg"></i>')
      );

      $li.on("dragstart", function (e) {
        dragFileId = entry.id;
        $(this).addClass("dragging");
        e.originalEvent.dataTransfer.effectAllowed = "move";
        e.originalEvent.dataTransfer.setData("text/plain", entry.id);
      });

      $li.on("dragend", function () {
        dragFileId = null;
        $(".file-queue-item").removeClass("dragging drag-over");
      });

      $li.on("dragover", function (e) {
        e.preventDefault();
        e.originalEvent.dataTransfer.dropEffect = "move";
        if (entry.id !== dragFileId) {
          $(this).addClass("drag-over");
        }
      });

      $li.on("dragleave", function () {
        $(this).removeClass("drag-over");
      });

      $li.on("drop", function (e) {
        e.preventDefault();
        e.stopPropagation();
        const srcId = e.originalEvent.dataTransfer.getData("text/plain") || dragFileId;
        const targetId = entry.id;
        if (!srcId || srcId === targetId) return;
        moveFileBefore(srcId, targetId);
      });

      $li.find(".fq-remove").on("click", function (e) {
        e.preventDefault();
        e.stopPropagation();
        removeFile(entry.id);
      });

      $fileList.append($li);
    });

    if (selectedFiles.length > 1) {
      const $actions = $('<li class="file-queue-actions">').append(
        $('<button type="button">')
          .addClass("btn btn-link text-danger p-0")
          .text("Xóa tất cả")
          .on("click", function (e) {
            e.preventDefault();
            e.stopPropagation();
            clearFiles();
          })
      );
      $fileList.append($actions);
    }

    updateProcessButton();
  }

  function moveFileBefore(srcId, targetId) {
    const srcIdx = selectedFiles.findIndex(function (x) { return x.id === srcId; });
    const tgtIdx = selectedFiles.findIndex(function (x) { return x.id === targetId; });
    if (srcIdx < 0 || tgtIdx < 0 || srcIdx === tgtIdx) return;
    const item = selectedFiles.splice(srcIdx, 1)[0];
    const insertAt = srcIdx < tgtIdx ? tgtIdx - 1 : tgtIdx;
    selectedFiles.splice(insertAt, 0, item);
    renderFileList();
  }

  function removeFile(id) {
    selectedFiles = selectedFiles.filter(function (x) { return x.id !== id; });
    renderFileList();
  }

  function clearFiles() {
    selectedFiles = [];
    $fileInput.val("");
    renderFileList();
  }

  function addFiles(fileList) {
    const incoming = Array.from(fileList || []);
    if (!incoming.length) return;

    const rejected = [];
    incoming.forEach(function (file) {
      if (!isPdfFile(file)) {
        rejected.push(file.name);
        return;
      }
      selectedFiles.push({ id: newFileId(), file: file });
    });

    if (rejected.length) {
      Swal.fire({
        icon: "warning",
        title: "Chỉ chấp nhận file PDF",
        text: rejected.join(", "),
        timer: 2500,
      });
    }

    renderFileList();
  }

  $fileInput.on("change", function () {
    if (this.files.length) {
      addFiles(this.files);
      this.value = "";
    }
  });

  $dropZone.on("dragover dragenter", function (e) {
    e.preventDefault();
    e.stopPropagation();
    $(this).addClass("dragover");
  });

  $dropZone.on("dragleave dragend drop", function (e) {
    e.preventDefault();
    e.stopPropagation();
    $(this).removeClass("dragover");
  });

  $dropZone.on("drop", function (e) {
    if (dragFileId) return;
    const dt = e.originalEvent.dataTransfer;
    if (!dt || !dt.files || !dt.files.length) return;
    addFiles(dt.files);
  });

  $dropZone.on("click", function (e) {
    if ($(e.target).closest(".file-queue-item, .file-queue-actions, label, input").length) {
      return;
    }
    $fileInput.trigger("click");
  });

  function updateProgress(job) {
    const pct = job.progress || 0;
    $progressBar.css("width", pct + "%").text(pct + "%");
    $progressPct.text(pct + "%");
    $progressMsg.text(job.message || "");
    const labels = {
      queued: "Đang chờ",
      read: "Đọc PDF",
      render: "Render trang",
      ocr: "OCR",
      analyze: "Phân tích",
      segment: "Phân đoạn",
      export: "Xuất file",
      done: "Hoàn tất",
    };
    $progressLabel.text(labels[job.phase] || "Đang xử lý...");
  }

  function renderReport(report, job) {
    $resultBody.empty();
    if (!report || !report.length) {
      $resultBody.append(
        $("<tr>").append(
          $("<td colspan='7' class='text-center text-muted py-4'>").text("Không có dữ liệu kết quả")
        )
      );
      $resultSummary.hide();
      updateJobActions(job);
      return;
    }
    report.forEach(function (row) {
      const tr = $("<tr>");
      tr.append($("<td>").text(row.stt));
      appendCopyCell(tr, row.ten_file);
      tr.append($("<td>").text(row.so_trang_goc));
      appendCopyCell(tr, row.loai_van_ban);
      appendCopyCell(tr, row.so_hieu);
      appendCopyCell(tr, row.trich_yeu, row.trich_yeu, "cell-trich-yeu");
      appendCopyCell(tr, row.ngay_ban_hanh, formatNgayBanHanh(row.ngay_ban_hanh));
      $resultBody.append(tr);
    });
    const fname = job && job.filename ? job.filename : "";
    $resultTitle.html('<i class="bi bi-table"></i> Kết quả — <span class="text-muted fw-normal">' + fname + "</span>");
    $resultSummary.text("Tổng: " + report.length + " văn bản").show();
    updateJobActions(job);
  }

  function renderHistoryList(items) {
    $historyList.find(".history-item").remove();
    $historyCount.text(items.length);

    if (!items.length) {
      $historyEmpty.show();
      return;
    }
    $historyEmpty.hide();

    items.forEach(function (item) {
      const $el = $('<div class="history-item" data-id="' + item.id + '">');
      if (item.id === currentJobId) {
        $el.addClass("active");
      }

      const docInfo = item.status === "completed"
        ? item.doc_count + " văn bản"
        : (item.status === "failed" ? "Thất bại"
          : (item.status === "cancelled" ? "Đã hủy" : "Đang xử lý"));

      const seqTag = item.folder_seq
        ? '<span class="hi-seq">#' + String(item.folder_seq).padStart(6, "0") + "</span> "
        : "";

      $el.html(
        '<div class="d-flex justify-content-between align-items-start gap-1">'
        + '<div class="hi-name" title="' + item.filename + '">'
        + seqTag + item.filename + "</div>"
        + '<div class="d-flex align-items-center gap-1">'
        + statusBadge(item.status)
        + '<button type="button" class="btn btn-link btn-sm p-0 hi-delete text-danger" title="Xóa">'
        + '<i class="bi bi-trash"></i></button>'
        + "</div></div>"
        + '<div class="hi-meta">' + formatDate(item.created_at) + " · " + docInfo + "</div>"
      );

      $el.find(".hi-delete").on("click", function (e) {
        e.stopPropagation();
        currentJobId = item.id;
        deleteCurrentJob();
      });

      $el.on("click", function (e) {
        if ($(e.target).closest(".hi-delete").length) return;
        loadJob(item.id);
      });

      $historyList.append($el);
    });

    if (currentJobId) {
      $historyList.find('[data-id="' + currentJobId + '"]').addClass("active");
    }
  }

  function loadHistory() {
    $.getJSON("/api/history", { _: Date.now() })
      .done(function (items) {
        items = items || [];
        renderHistoryList(items);

        if (!pollTimer) {
          const running = items.find(function (item) {
            return item.status === "running" || item.status === "queued";
          });
          if (running) {
            ensurePolling(running.id);
          }
        }
      })
      .fail(function () {
        $.getJSON("/api/jobs")
          .done(function (items) {
            renderHistoryList(items || []);
          })
          .fail(function () {
            console.warn("Không tải được lịch sử");
          });
      });
  }

  function loadJob(jobId, options) {
    const opts = options || {};
    const startPoll = opts.startPoll !== false;
    currentJobId = jobId;
    $historyList.find(".history-item").removeClass("active");
    $historyList.find('[data-id="' + jobId + '"]').addClass("active");

    $.getJSON("/api/jobs/" + jobId, { _: Date.now() })
      .done(function (job) {
        applyJobView(job);

        if (isActiveJob(job) && startPoll) {
          ensurePolling(jobId);
        }

        loadHistory();
      })
      .fail(function () {
        Swal.fire({ icon: "error", title: "Không tải được công việc" });
      });
  }

  function isActiveJob(job) {
    return job.status === "running" || job.status === "queued";
  }

  function applyJobConfig(job) {
    if (!job.config) return;
    if (job.config.doc_profile) {
      $docProfile.val(job.config.doc_profile);
    }
    if (job.config.prefix) {
      $prefix.val(job.config.prefix);
    } else if (job.config.doc_profile) {
      applyProfilePrefix(job.config.doc_profile);
    }
  }

  function applyJobView(job) {
    $("#emptyRow").remove();
    $progressCard.show();
    applyJobConfig(job);

    if (isActiveJob(job)) {
      updateProgress(job);
      $progressBar.addClass("progress-bar-animated progress-bar-striped").removeClass("bg-danger bg-warning");
      $btnCancelJob.prop("disabled", false).show();
      renderReport(null, job);
      updateJobActions(job);
      return;
    }

    $btnCancelJob.hide();

    if (job.status === "completed") {
      $progressBar.css("width", "100%").text("100%").removeClass("progress-bar-animated bg-danger bg-warning");
      $progressPct.text("100%");
      $progressMsg.text(job.message);
      $progressLabel.text("Hoàn tất");
      $btnProcess.prop("disabled", false);
      renderReport(job.report, job);
      return;
    }

    $btnProcess.prop("disabled", false);

    if (job.status === "cancelled") {
      const pct = job.progress || 0;
      $progressBar.css("width", pct + "%").text(pct + "%")
        .removeClass("progress-bar-animated progress-bar-striped").addClass("bg-warning");
      $progressPct.text(pct + "%");
      $progressMsg.text(job.error || job.message);
      $progressLabel.text("Đã hủy");
      renderReport(null, job);
      updateJobActions(job);
      return;
    }

    const pctFail = job.progress || 0;
    $progressBar.css("width", pctFail + "%").text(pctFail + "%")
      .removeClass("progress-bar-animated progress-bar-striped").addClass("bg-danger");
    $progressPct.text(pctFail + "%");
    $progressMsg.text(job.error || job.message);
    $progressLabel.text("Lỗi");
    renderReport(null, job);
    updateJobActions(job);
  }

  function notifyJobFinished(job) {
    if (job.status === "completed") {
      Swal.fire({
        icon: "success",
        title: "Hoàn tất!",
        text: job.message,
        timer: 2500,
        showConfirmButton: false,
      });
    } else if (job.status === "cancelled") {
      Swal.fire({
        icon: "info",
        title: "Đã hủy",
        text: job.message,
        timer: 2000,
        showConfirmButton: false,
      });
    } else if (job.status === "failed") {
      Swal.fire({
        icon: "error",
        title: "Lỗi xử lý",
        text: job.error || job.message,
      });
    }
  }

  function handlePollResult(job, polledJobId, options) {
    const opts = options || {};
    const notify = opts.notify !== false;
    const isViewing = currentJobId === polledJobId;

    if (isActiveJob(job)) {
      if (isViewing) {
        updateProgress(job);
      }
      return;
    }

    if (pollingJobId === polledJobId) {
      stopPolling();
    }

    loadHistory();

    if (isViewing) {
      applyJobView(job);
      if (notify) {
        notifyJobFinished(job);
      }
    }
  }

  function stopPolling() {
    if (pollTimer) {
      clearInterval(pollTimer);
      pollTimer = null;
    }
    pollingJobId = null;
  }

  function ensurePolling(jobId) {
    if (pollingJobId === jobId && pollTimer) {
      return;
    }
    stopPolling();
    pollingJobId = jobId;
    pollTimer = setInterval(function () {
      $.getJSON("/api/jobs/" + jobId, { _: Date.now() })
        .done(function (job) {
          handlePollResult(job, jobId);
        })
        .fail(function () {
          stopPolling();
          if (currentJobId === jobId) {
            $btnProcess.prop("disabled", false);
            Swal.fire({ icon: "error", title: "Mất kết nối server" });
          }
        });
    }, 800);
  }

  $("#processForm").on("submit", function (e) {
    e.preventDefault();
    if (!selectedFiles.length) {
      Swal.fire({ icon: "warning", title: "Vui lòng chọn file PDF" });
      return;
    }

    const formData = new FormData();
    selectedFiles.forEach(function (entry) {
      formData.append("files", entry.file);
    });
    formData.append("prefix", $("#prefix").val());
    formData.append("phong", $("#phong").val());
    formData.append("version", $("#version").val());
    formData.append("date_scan", $("#dateScan").val());
    formData.append("lang", $("#lang").val());
    formData.append("dpi", $("#dpi").val());
    formData.append("doc_profile", $("#docProfile").val());
    formData.append("ocr_workers", $("#ocrWorkers").val());

    $btnProcess.prop("disabled", true);
    $resultActions.hide();
    $btnCancelJob.hide();
    $resultSummary.hide();
    $("#emptyRow").remove();
    $resultBody.empty();
    $progressCard.show();
    $progressBar.css("width", "0%").text("0%").removeClass("bg-danger").addClass("progress-bar-animated");
    $progressPct.text("0%");
    $progressMsg.text("Đang tải lên...");

    $.ajax({
      url: "/api/process",
      type: "POST",
      data: formData,
      processData: false,
      contentType: false,
    })
      .done(function (res) {
        currentJobId = res.job_id;
        loadHistory();
        loadJob(currentJobId, { startPoll: true });
        if (res.trial_notice) {
          Swal.fire({
            icon: "info",
            title: "Bản dùng thử",
            text: res.trial_notice,
            confirmButtonText: "Tiếp tục",
          });
        }
      })
      .fail(function (xhr) {
        $btnProcess.prop("disabled", false);
        let msg = "Upload thất bại";
        if (xhr.responseJSON && xhr.responseJSON.detail) {
          msg = xhr.responseJSON.detail;
        }
        if (xhr.status === 403) {
          Swal.fire({ icon: "warning", title: "Cần kích hoạt", text: msg }).then(function () {
            openLicenseModal();
          });
        } else {
          Swal.fire({ icon: "error", title: "Lỗi", text: msg });
        }
      });
  });

  $("#btnDownload").on("click", function () {
    if (!currentJobId) return;

    function downloadBlob() {
      fetch("/api/jobs/" + currentJobId + "/download")
        .then(function (res) {
          if (!res.ok) throw new Error("Tải ZIP thất bại");
          return res.blob();
        })
        .then(function (blob) {
          const url = URL.createObjectURL(blob);
          const a = document.createElement("a");
          a.href = url;
          a.download = "PDFEX_" + currentJobId + ".zip";
          document.body.appendChild(a);
          a.click();
          a.remove();
          URL.revokeObjectURL(url);
          Swal.fire({ icon: "success", title: "Đã tải ZIP", timer: 2000, showConfirmButton: false });
        })
        .catch(function (err) {
          Swal.fire({ icon: "error", title: "Lỗi tải ZIP", text: err.message });
        });
    }

    if (window.pywebview && window.pywebview.api && window.pywebview.api.download_zip) {
      window.pywebview.api.download_zip(currentJobId).then(function (res) {
        if (res.ok) {
          Swal.fire({ icon: "success", title: "Đã lưu ZIP", text: res.path, timer: 3500 });
        } else if (!res.cancelled) {
          Swal.fire({ icon: "error", title: "Lỗi", text: res.error || "Không lưu được ZIP" });
        }
      }).catch(function () {
        downloadBlob();
      });
    } else {
      downloadBlob();
    }
  });

  $("#btnOpenFolder").on("click", function () {
    if (!currentJobId) return;
    if (window.pywebview && window.pywebview.api && window.pywebview.api.open_output_folder) {
      window.pywebview.api.open_output_folder(currentJobId).then(function (res) {
        if (!res.ok) {
          Swal.fire({ icon: "error", title: "Lỗi", text: res.error });
        }
      });
      return;
    }
    $.post("/api/jobs/" + currentJobId + "/open-folder")
      .fail(function () {
        Swal.fire({ icon: "error", title: "Không mở được thư mục" });
      });
  });

  $("#btnCancelJob").on("click", function () {
    if (!currentJobId) return;
    Swal.fire({
      icon: "question",
      title: "Hủy xử lý?",
      text: "Tiến trình OCR/tách PDF sẽ dừng.",
      showCancelButton: true,
      confirmButtonText: "Hủy job",
      cancelButtonText: "Tiếp tục",
    }).then(function (result) {
      if (!result.isConfirmed) return;
      $.post("/api/jobs/" + currentJobId + "/cancel")
        .done(function () {
          $progressMsg.text("Đang hủy...");
          $btnCancelJob.prop("disabled", true);
        })
        .fail(function (xhr) {
          const msg = xhr.responseJSON && xhr.responseJSON.detail
            ? xhr.responseJSON.detail : "Không hủy được";
          Swal.fire({ icon: "error", title: "Lỗi", text: msg });
        });
    });
  });

  $("#btnDeleteJob").on("click", function () {
    deleteCurrentJob();
  });

  if (!$("#dateScan").val()) {
    const now = new Date();
    const dd = String(now.getDate()).padStart(2, "0");
    const mm = String(now.getMonth() + 1).padStart(2, "0");
    const yyyy = now.getFullYear();
    $("#dateScan").val(yyyy + mm + dd);
  }

  loadDocProfiles();
  loadHistory();
  loadLicenseStatus();
  $.getJSON("/api/about").done(function (data) {
    aboutInfo = data;
    $("#navTagline").text((data.tagline || "") + " v" + (data.version || "").split(".")[0]);
  });
})(jQuery);
