/* global api, state, number, escapeHtml, mediaUrl, extensionMessage, showToast, IS_EXTENSION_SURFACE */
(function collaborationPerformanceV2() {
  "use strict";

  // Chữ ký bắt tay đi cùng lệnh đồng bộ. Service worker sẽ từ chối ngay nếu
  // dashboard và extension không cùng bộ mã, thay vì để server báo chung chung
  // là "worker cũ" sau khi người dùng đã bấm chạy.
  const COLLAB_CLIENT_PROTOCOL = "collab-v2-progressive";
  const COLLAB_DASHBOARD_BUILD = "6.0.36";
  const COLORS = Object.freeze({ purple: "#6e4ae8", orange: "#e9792f", pink: "#d84c8e", blue: "#3e8ed0", danger: "#d94c4c" });

  const ui = {
    summary: null,
    trends: null,
    loading: false,
    drawerIssue: "",
    drawerLabel: "",
    drawerPage: 1,
    drawerKind: "",
    drawerKeyword: "",
    activePanel: "campaigns",
    syncProgress: null,
    liveRefreshTimer: 0,
    liveRefreshPending: false,
    lastLiveSignature: "",
    sourceProgress: {},
    sourceRunId: "",
  };
  const statusLabels = { 1: "Đang diễn ra", 2: "Sắp hết hạn", 3: "Sắp kết thúc", 4: "Đã hoàn tất" };
  const stageLabels = {
    pending_review: "Chờ xem xét", ready_to_ship: "Sẵn sàng vận chuyển", shipped: "Đã vận chuyển",
    in_progress: "Đang tiến hành", completed: "Đã hoàn thành", refunded: "Đã hoàn tiền",
    unrefunded: "Chưa hoàn tiền", cancelled: "Đã hủy", rejected: "Đã từ chối", unknown: "Chưa xác định",
  };
  const issueMeta = {
    no_video: { label: "Chưa có video", hint: "Đã quét thành công nhưng TikTok trả về rỗng", color: COLORS.pink },
    video_unknown: { label: "Video chưa xác định", hint: "Chưa quét hoặc lần quét gần nhất bị lỗi", color: COLORS.orange },
    overdue: { label: "Quá hạn thực hiện", hint: "Đã qua hạn nhưng chưa hoàn thành", color: COLORS.danger },
    unrefunded: { label: "Chưa hoàn tiền", hint: "Đã tới bước cần hoàn tiền", color: COLORS.purple },
    lost: { label: "Mất dấu dữ liệu", hint: "Vắng mặt sau hai lần đối soát đầy đủ", color: COLORS.danger },
  };

  const $ = id => document.getElementById(id);
  const n = value => Number(value || 0);
  const fmt = value => typeof number === "function" ? number(n(value)) : n(value).toLocaleString("vi-VN");
  const money = (value, currency = "VND") => new Intl.NumberFormat("vi-VN", {
    style: "currency", currency: currency === "MULTI" ? "VND" : currency || "VND", maximumFractionDigits: 0,
  }).format(n(value));
  const safeDate = value => {
    const date = value ? new Date(value) : null;
    return date && Number.isFinite(date.getTime()) ? date.toLocaleString("vi-VN") : "—";
  };
  const shopQuery = () => `shopId=${encodeURIComponent(String(state?.shopId || ""))}&region=${encodeURIComponent(String(state?.region || "VN"))}`;
  const periodDays = () => Math.max(7, Number($("cpPeriod")?.value || 30));
  const newTraceId = () => `cp_${Date.now().toString(36)}_${crypto.randomUUID().slice(0, 8)}`;

  function traceLog(traceId, stage, detail = {}, level = "info") {
    const safe = detail && typeof detail === "object" ? detail : { detail: String(detail || "") };
    const method = level === "error" ? "error" : level === "warn" ? "warn" : "info";
    try { console[method](`[COLLAB-TRACE ${traceId}] ${stage}`, safe); } catch {}
  }

  function setCampaignPanel(active) {
    ui.activePanel = active ? "campaigns" : "performance";
    const performance = $("collabPerformancePanel");
    const filter = $("collabFilter");
    const table = $("collabRows")?.closest(".table-shell");
    const tableTools = document.querySelector("#collabView .collab-table-tools");
    const target = $("collabTargetOverview");
    if (performance) performance.hidden = active;
    if (filter) filter.hidden = !active;
    if (table) table.hidden = !active;
    if (tableTools) tableTools.hidden = !active;
    if (target) target.hidden = !active;
    document.querySelector("#collabView .collab-menu-wrap")?.toggleAttribute("hidden", !active);
    $("refreshCollab")?.toggleAttribute("hidden", !active);
    document.querySelectorAll("#collabView .an-subtab").forEach(button => {
      if (button.dataset.subview === "collab-performance") button.classList.toggle("active", !active);
      else if (button.dataset.subview === "collab") button.classList.toggle("active", active);
      else if (!active) button.classList.remove("active");
    });
    if (!active) {
      // Cả App và Extension đều dựng dashboard từ projection trên server. App không
      // gọi TikTok ngay khi vừa chuyển tab: lượt Open API có thể bị giới hạn hoặc
      // chậm, nhưng snapshot đã lưu vẫn phải mở được ngay và không được trắng màn.
      loadDashboard().catch(error => notifyError("Không tải được hiệu suất hàng mẫu", error));
    }
  }
  globalThis.setCollabCampaignPanel = setCampaignPanel;

  function notifyError(title, error) {
    const traceId = String(error?.traceId || error?.data?.traceId || "");
    const stage = String(error?.stage || error?.data?.stage || "");
    const status = Number(error?.status || error?.data?.status || 0);
    const diagnostic = [stage ? `chặng ${stage}` : "", status ? `HTTP ${status}` : "", traceId ? `mã ${traceId}` : ""].filter(Boolean).join(" · ");
    const message = `${String(error?.message || error || "Lỗi không xác định")}${diagnostic ? `\nKiểm tra: ${diagnostic}` : ""}`;
    if (traceId) traceLog(traceId, stage || "dashboard:error", { title, status, message: String(error?.message || error || "") }, "error");
    if (typeof showToast === "function") showToast(title, message, "error", 9000);
  }

  async function loadDashboard(options = {}) {
    if (!state?.shopId) return;
    if (ui.loading) {
      if (options.live === true) ui.liveRefreshPending = true;
      return;
    }
    ui.loading = true;
    const refresh = options.refresh === true;
    const live = options.live === true;
    const panel = $("collabPerformancePanel");
    panel?.setAttribute("aria-busy", "true");
    try {
      const days = periodDays();
      const suffix = `${shopQuery()}&days=${days}${live ? "&live=1" : ""}${refresh ? `&_=${Date.now()}` : ""}`;
      const [summaryResult, trendsResult] = await Promise.allSettled([
        api(`/api/v1/collab-dashboard/summary?${suffix}`),
        api(`/api/v1/collab-dashboard/trends?${suffix}`),
      ]);
      if (summaryResult.status === "fulfilled") ui.summary = summaryResult.value || {};
      if (trendsResult.status === "fulfilled") ui.trends = trendsResult.value || {};
      if (summaryResult.status === "rejected" && trendsResult.status === "rejected") {
        throw summaryResult.reason || trendsResult.reason;
      }
      if (summaryResult.status === "rejected" || trendsResult.status === "rejected") {
        const missing = summaryResult.status === "rejected" ? "tổng quan" : "xu hướng";
        showToast("Dữ liệu chưa đầy đủ", `Đã giữ phần tải được; phần ${missing} sẽ tự thử lại.`, "warning", 7000);
      }
      renderDashboard();
      return ui.summary;
    } finally {
      ui.loading = false;
      panel?.removeAttribute("aria-busy");
      if (ui.liveRefreshPending) {
        ui.liveRefreshPending = false;
        setTimeout(() => loadDashboard({ live: true, refresh: true }).catch(() => {}), 0);
      }
    }
  }

  function delta(current, previous) {
    const cur = n(current), prev = n(previous);
    if (!prev) return cur ? "+ mới" : "Không đổi";
    const value = (cur - prev) / prev * 100;
    return `${value >= 0 ? "+" : ""}${value.toFixed(0)}% so kỳ trước`;
  }

  function renderDashboard() {
    const summary = ui.summary || {};
    const kpi = summary.kpis || {};
    const issues = summary.issues || {};
    const video = summary.videoPerformance || {};
    const finance = summary.refundFinance || {};
    const requestCompletionRate = n(kpi.requests) ? n(kpi.completedRequests) / n(kpi.requests) * 100 : 0;
    const setText = (id, value) => { const element = $(id); if (element) element.textContent = value; };
    setText("cpApproved", fmt(kpi.requests));
    setText("cpSent", fmt(kpi.sentRequests));
    setText("cpWaiting", fmt(kpi.waitingRequests));
    setText("cpCompleted", fmt(kpi.completedRequests));
    setText("cpCancelled", fmt(kpi.cancelledRequests));
    setText("cpNoVideo", fmt(issues.no_video_requests));
    setText("cpApprovedSub", `${fmt(kpi.approved)} KOC duy nhất · ${delta(kpi.approved, kpi.previousApproved)}`);
    setText("cpWaitingSub", `${fmt(kpi.waiting)} KOC cần theo dõi`);
    setText("cpCancelledSub", `${fmt(kpi.cancelled)} KOC`);
    setText("cpNoVideoSub", `${fmt(issues.no_video)} KOC cần xử lý`);
    setText("cpCompleteRate", `${fmt(kpi.completed)} KOC · ${requestCompletionRate.toLocaleString("vi-VN", { maximumFractionDigits: 1 })}% mẫu`);
    setText("cpFlowRate", `${requestCompletionRate.toLocaleString("vi-VN", { maximumFractionDigits: 1 })}% hoàn thành`);
    setText("cpCreatorsWithVideo", fmt(video.creatorsWithVideo));
    setText("cpVideoCoverage", `Độ phủ ${n(video.videoCoverageRate).toLocaleString("vi-VN")}% KOC đã duyệt`);
    setText("cpVideoCount", fmt(video.videos));
    setText("cpVideoViews", fmt(video.views));
    setText("cpVideoEngagement", `${fmt(n(video.likes) + n(video.comments))} lượt thích + bình luận`);
    setText("cpVideoOrders", fmt(video.paidOrders));
    setText("cpOrdersPerView", `${n(video.ordersPerThousandViews).toLocaleString("vi-VN")} đơn / 1.000 lượt xem`);
    setText("cpRefundCost", money(finance.amount, finance.currency));
    const refundDateNote = n(finance.requestsWithDate) && finance.latestRefundedAt
      ? `Gần nhất ${safeDate(finance.latestRefundedAt)}`
      : "API danh sách chưa có ngày hoàn";
    setText("cpRefundCostSub", `${fmt(finance.requestsWithAmount)}/${fmt(finance.refundedRequests)} mẫu · TB ${money(finance.averageAmount, finance.currency)}/mẫu · ${refundDateNote}`);
    const sentRate = n(kpi.requests) ? n(kpi.sentRequests) / n(kpi.requests) * 100 : 0;
    const insight = $("cpExecutiveInsight");
    if (insight) insight.innerHTML = `<strong>${fmt(kpi.sentRequests)}/${fmt(kpi.requests)} mẫu đã gửi (${sentRate.toLocaleString("vi-VN", { maximumFractionDigits: 1 })}%)</strong><span>Nút thắt hiện tại: <b>${fmt(kpi.waitingRequests)} mẫu đang chờ</b> · <b>${fmt(issues.no_video_requests)} mẫu chưa có video</b> · tạo <b>${fmt(video.paidOrders)} đơn hàng</b>.</span>`;
    setText("cpBaselineText", summary.baselineAt
      ? `Ghi nhận từ ${safeDate(summary.baselineAt)} · ${fmt(kpi.requests)} mẫu thuộc ${fmt(kpi.approved)} KOC duy nhất`
      : "Chưa có mốc dữ liệu. Bấm Cập nhật nhanh để tạo baseline đầu tiên.");
    const latest = summary.latestSync;
    const latestMode = latest?.mode === "incremental" ? "Cập nhật nhanh" : "Đối soát đầy đủ";
    setText("cpSyncTime", latest?.finished_at
      ? `${latestMode} · ${safeDate(latest.finished_at)}`
      : latest?.started_at ? `Đang đồng bộ từ ${safeDate(latest.started_at)}` : "Chưa đồng bộ");
    renderTargetOverview(summary.targetStatuses || []);
    renderFlow(summary.sampleFlow || [], kpi);
    renderCompare(summary.sampleKinds || []);
    renderIssues(issues);
    renderRefundFlow(summary.refundableFlow || []);
    renderTrend(ui.trends?.samples || []);
    renderSourceCharts(ui.syncProgress, summary);
    renderPartialState(summary);
  }

  function renderOfficialSampleQuick(records = []) {
    const rows = Array.isArray(records) ? records : [];
    const setText = (id, value) => { const element = $(id); if (element) element.textContent = value; };
    const creatorKey = row => String(row.creatorOecId || row.creatorHandle || row.id || row.stableKey || "");
    const unique = subset => new Set(subset.map(creatorKey).filter(Boolean)).size;
    const stage = row => String(row.status || "pending_review");
    const approvedRows = rows.filter(row => !["pending_review", "rejected", "cancelled"].includes(stage(row)));
    const waitingRows = rows.filter(row => ["ready_to_ship", "approved"].includes(stage(row)));
    const sentRows = rows.filter(row => ["shipped", "in_progress", "completed"].includes(stage(row)));
    const completedRows = rows.filter(row => stage(row) === "completed");
    const cancelledRows = rows.filter(row => ["rejected", "cancelled"].includes(stage(row)));
    setText("cpApproved", fmt(approvedRows.length));
    setText("cpApprovedSub", `${fmt(unique(approvedRows))} KOC · trang mới nhất`);
    setText("cpSent", fmt(sentRows.length));
    setText("cpSentSub", "Đã rời bước chờ gửi");
    setText("cpWaiting", fmt(waitingRows.length));
    setText("cpWaitingSub", `${fmt(unique(waitingRows))} KOC cần theo dõi`);
    setText("cpCompleted", fmt(completedRows.length));
    setText("cpCompleteRate", approvedRows.length ? `${(completedRows.length / approvedRows.length * 100).toLocaleString("vi-VN", { maximumFractionDigits: 1 })}% trên trang` : "0%");
    setText("cpCancelled", fmt(cancelledRows.length));
    setText("cpCancelledSub", `${fmt(unique(cancelledRows))} KOC`);
    // Open API danh sách mẫu cho biết trạng thái vòng đời nhưng không trả KPI video/
    // hoàn tiền trong cùng response. Xóa số snapshot Extension cũ để không trộn hai
    // nguồn rồi hiển thị một con số có vẻ hợp lệ nhưng thực tế sai.
    setText("cpNoVideo", "—");
    setText("cpNoVideoSub", "Cần đọc nội dung hoàn thành");
    setText("cpCreatorsWithVideo", "—");
    setText("cpVideoCoverage", "Chưa đối soát nội dung");
    setText("cpVideoCount", "—");
    setText("cpVideoViews", "—");
    setText("cpVideoEngagement", "Chưa có trong API danh sách mẫu");
    setText("cpVideoOrders", "—");
    setText("cpOrdersPerView", "Chưa có trong API danh sách mẫu");
    setText("cpRefundCost", "—");
    setText("cpRefundCostSub", "Cần đối soát từng yêu cầu đã hoàn thành");
    setText("cpBaselineText", `Open API · ${fmt(rows.length)} yêu cầu theo các trạng thái đã đọc`);
    setText("cpSyncTime", `Open API · ${safeDate(new Date())}`);
    const insight = $("cpExecutiveInsight");
    if (insight) insight.innerHTML = `<strong>${fmt(sentRows.length)}/${fmt(rows.length)} mẫu đã rời bước chờ gửi</strong><span>${fmt(waitingRows.length)} mẫu đang chờ · ${fmt(completedRows.length)} mẫu hoàn tất · ${fmt(cancelledRows.length)} mẫu đã hủy/từ chối.</span>`;
  }

  async function loadOfficialSampleDashboard() {
    if (!state?.shopId) return;
    const shopId = encodeURIComponent(String(state.shopId));
    // TikTok trả total_count=9.999 không phản ánh bộ lọc và còn có lịch sử nhiều
    // trạng thái. Chỉ đọc trang mới nhất rồi phân loại theo status thật; số yêu
    // cầu đã duyệt và số KOC được tính lại từ chính các dòng đã phân loại.
    const page = await api(`/api/v1/openapi/tiktok/shops/${shopId}/sample-applications/search`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ page: 1, pageSize: 50 }),
    });
    const uniqueRows = new Map();
    (Array.isArray(page?.records) ? page.records : []).forEach(record => {
      const key = String(record?.id || record?.applyId || record?.stableKey || "");
      if (key) uniqueRows.set(key, record);
    });
    const records = Array.from(uniqueRows.values());
    renderOfficialSampleQuick(records);
    return records;
  }

  function renderSourceCharts(progress, summary = ui.summary || {}) {
    const target = $("cpSourceCharts");
    if (!target) return;
    const runId = String(progress?.runId || "");
    if (runId && runId !== ui.sourceRunId) {
      ui.sourceRunId = runId;
      ui.sourceProgress = {};
    }
    if (progress?.sources && typeof progress.sources === "object") ui.sourceProgress = { ...ui.sourceProgress, ...progress.sources };
    const fallbackTarget = (summary.targetStatuses || []).reduce((sum, row) => sum + n(row.groups), 0);
    const kinds = new Map((summary.sampleKinds || []).map(row => [row.sample_kind, row]));
    const latestDone = summary.latestSync?.status === "completed";
    const configs = [
      ["target_groups", "Cộng tác mục tiêu", fallbackTarget, "bản ghi"],
      ["sample_free", "Hàng mẫu miễn phí", n(kinds.get("free")?.approved), "KOC đã duyệt"],
      ["sample_refundable", "Hàng mẫu hoàn tiền", n(kinds.get("refundable")?.approved), "KOC đã duyệt"],
    ];
    let completed = 0;
    target.innerHTML = configs.map(([key, label, fallback, unit]) => {
      const source = ui.sourceProgress[key] || {};
      const value = fallback || source.accepted;
      const current = n(source.current), total = n(source.total);
      const complete = source.complete === true || (!progress || progress.status !== "running") && latestDone && value > 0;
      if (complete) completed += 1;
      const percent = complete ? 100 : total ? Math.min(100, current / total * 100) : current ? 18 : value ? 100 : 0;
      const status = complete ? "Đã chốt riêng" : current ? "Đang cập nhật" : value ? "Đã có dữ liệu" : "Chờ dữ liệu";
      const detail = total ? `Đọc ${fmt(current)}/${fmt(total)} dòng · server nhận ${fmt(value)}` : value ? `${fmt(value)} ${unit}` : "Chưa nhận lô hợp lệ";
      return `<article class="cp-source-chart ${complete ? "is-complete" : ""}" data-source="${key}"><div><h4>${escapeHtml(label)}</h4><b>${escapeHtml(status)}</b></div><strong>${value ? fmt(value) : "—"}</strong><small>${escapeHtml(detail)}</small><div class="cp-source-track"><i style="width:${percent.toFixed(1)}%"></i></div></article>`;
    }).join("");
    const done = $("cpSourceDone");
    if (done) done.textContent = `${completed}/3 nguồn đã chốt`;
  }

  function renderPartialState(summary) {
    const progress = ui.syncProgress || {};
    if (progress.status !== "running") return;
    const current = n(progress.current), total = n(progress.total);
    const progressText = total ? `${fmt(current)}/${fmt(total)}` : current ? fmt(current) : "lô đầu tiên";
    if ($("cpSyncTime")) $("cpSyncTime").textContent = `Dữ liệu tạm · đang xử lý ${progressText}`;
    if (n(summary?.kpis?.requests) > 0) {
      if ($("cpBaselineText")) $("cpBaselineText").textContent = `Biểu đồ đang tự cập nhật theo các lô đã lưu (${progressText}); số cuối được chốt khi đồng bộ hoàn tất.`;
      return;
    }
    ["cpApproved", "cpSent", "cpWaiting", "cpCompleted", "cpCancelled", "cpNoVideo", "cpCreatorsWithVideo", "cpVideoCount", "cpVideoViews", "cpVideoOrders"].forEach(id => { if ($(id)) $(id).textContent = "…"; });
    if ($("cpApprovedSub")) $("cpApprovedSub").textContent = "Đang chờ lô hàng mẫu đầu tiên";
    if ($("cpCompleteRate")) $("cpCompleteRate").textContent = "Đang tạo số liệu tạm";
    if ($("cpFlowRate")) $("cpFlowRate").textContent = "Đang chuẩn bị";
    if ($("cpBaselineText")) $("cpBaselineText").textContent = progress.step === "target_groups"
      ? `Đang cập nhật dữ liệu cộng tác mục tiêu (${progressText}); hiệu suất hàng mẫu sẽ xuất hiện ngay khi nhận lô đầu tiên.`
      : `Đang nhận lô hàng mẫu đầu tiên (${progressText}); biểu đồ sẽ tự xuất hiện và tăng dần, không cần chờ tải xong.`;
    if ($("cpFlow")) $("cpFlow").innerHTML = '<div class="cp-live-placeholder">Đang nhận dữ liệu hàng mẫu…</div>';
    if ($("cpFlowLegend")) $("cpFlowLegend").innerHTML = '<span class="cp-live-note">Số liệu tạm sẽ cập nhật theo từng lô 50 dòng</span>';
    if ($("cpCompare")) $("cpCompare").innerHTML = '<div class="cp-live-placeholder">Đang chuẩn bị so sánh miễn phí và hoàn tiền…</div>';
    if ($("cpIssues")) $("cpIssues").innerHTML = '<div class="cp-live-placeholder">Đang phân loại các vấn đề cần xử lý…</div>';
    if ($("cpRefundFlow")) $("cpRefundFlow").innerHTML = '<div class="cp-live-placeholder">Đang tải tiến độ hàng mẫu hoàn tiền…</div>';
    if ($("cpTrend")) $("cpTrend").innerHTML = '<text x="50%" y="50%" text-anchor="middle" class="cp-trend-loading">Đang dựng xu hướng từ dữ liệu đã nhận…</text>';
  }

  function scheduleLiveRefresh(progress) {
    if (progress?.status !== "running" || ui.activePanel !== "performance") return;
    const current = n(progress.current);
    if (current < 1) return;
    const signature = `${progress.step || "sync"}:${current}:${n(progress.total)}`;
    if (signature === ui.lastLiveSignature) return;
    ui.lastLiveSignature = signature;
    clearTimeout(ui.liveRefreshTimer);
    ui.liveRefreshTimer = setTimeout(() => {
      loadDashboard({ live: true, refresh: true }).catch(error => notifyError("Chưa cập nhật được số liệu tạm", error));
    }, 900);
  }

  function renderTargetOverview(rows, { fromSummaryAPI = false } = {}) {
    // Chỉ lưu summary khi dữ liệu đến từ summary API (có cả 4 status),
    // KHÔNG ghi đè khi được gọi từ renderTargetOverviewFromList (chỉ có 1 status).
    if (fromSummaryAPI && Array.isArray(rows) && rows.length > 0) {
      globalThis._collabServerSummaryStatuses = rows;
    }
    const targetRows = (globalThis._collabServerSummaryStatuses && globalThis._collabServerSummaryStatuses.length)
      ? globalThis._collabServerSummaryStatuses
      : (rows || []);
    const values = new Map((Array.isArray(targetRows) ? targetRows : []).map(row => [Number(row.status), row]));
    const target = $("collabTargetOverview");
    if (!target) return;
    const selectedStatus = String($("cfStatus")?.value || "");
    const existingButtons = target.querySelectorAll("button.cp-target-stat");
    if (existingButtons.length === 4) {
      existingButtons.forEach(btn => {
        const status = Number(btn.dataset.status);
        const row = values.get(status) || {};
        const strong = btn.querySelector("strong");
        if (strong) strong.textContent = fmt(row.groups || 0);
        const active = !!selectedStatus && String(status) === selectedStatus;
        btn.classList.toggle("active", active);
        btn.setAttribute("aria-pressed", String(active));
      });
      return;
    }
    target.innerHTML = [1, 2, 3, 4].map(status => {
      const row = values.get(status) || {};
      const active = selectedStatus === String(status);
      return `<button class="cp-target-stat${active ? " active" : ""}" type="button" data-status="${status}" aria-pressed="${active}" title="Lọc bảng theo trạng thái ${escapeHtml(statusLabels[status])}; bấm lại để bỏ lọc"><span>${escapeHtml(statusLabels[status])}</span><strong>${fmt(row.groups)}</strong></button>`;
    }).join("");
    target.querySelectorAll("button").forEach(button => button.addEventListener("click", () => {
      const statusInput = $("cfStatus");
      if (statusInput) {
        statusInput.value = statusInput.value === button.dataset.status ? "" : button.dataset.status;
        statusInput.dispatchEvent(new Event("change", { bubbles: true }));
      }
    }));
  }

  function renderTargetOverviewFromList(records) {
    // Luôn ưu tiên dữ liệu summary từ server — chỉ cập nhật active state.
    if (globalThis._collabServerSummaryStatuses && globalThis._collabServerSummaryStatuses.length) {
      renderTargetOverview(globalThis._collabServerSummaryStatuses);
      return;
    }
    const counts = new Map([1, 2, 3, 4].map(status => [status, 0]));
    const seen = new Set();
    for (const item of Array.isArray(records) ? records : []) {
      const id = String(item?.id || item?.invitationGroupId || "").trim();
      const status = Number(item?.status || item?.groupStatus || 0);
      if (!id || !counts.has(status) || seen.has(id)) continue;
      seen.add(id);
      counts.set(status, counts.get(status) + 1);
    }
    const list = [1, 2, 3, 4].map(status => ({ status, groups: counts.get(status) }));
    renderTargetOverview(list);
  }
  globalThis.renderCollabTargetOverviewFromList = renderTargetOverviewFromList;
  globalThis.renderCollabTargetOverview = renderTargetOverview;

  function renderFlow(rows, kpi = {}) {
    const values = new Map((Array.isArray(rows) ? rows : []).map(row => [String(row.stage || ""), n(row.requests)]));
    const items = [
      ["approved", "Đã duyệt", n(kpi.requests), COLORS.purple, 100],
      ["sent", "Đã gửi", n(kpi.sentRequests), COLORS.pink, n(kpi.requests) ? n(kpi.sentRequests) / n(kpi.requests) * 100 : 0],
      ["waiting", "Đang chờ", n(kpi.waitingRequests), COLORS.orange, n(kpi.sentRequests) ? n(kpi.waitingRequests) / n(kpi.sentRequests) * 100 : 0],
      ["completed", "Hoàn thành", n(kpi.completedRequests), COLORS.blue, n(kpi.sentRequests) ? n(kpi.completedRequests) / n(kpi.sentRequests) * 100 : 0],
    ];
    const flow = $("cpFlow"), legend = $("cpFlowLegend");
    if (!flow || !legend) return;
    flow.innerHTML = items.map(([key, label, value, color, rate], index) => `<button class="cp-flow-stage ${key}" type="button" data-drill="${key}" style="--stage-color:${color}" title="${escapeHtml(label)}: ${fmt(value)} mẫu"><small>Bước ${index + 1}</small><strong>${fmt(value)}</strong><span>${escapeHtml(label)}</span><i>${n(rate).toLocaleString("vi-VN", { maximumFractionDigits: 1 })}%</i></button>`).join("");
    const cancelled = n(kpi.cancelledRequests) || n(values.get("cancelled")) + n(values.get("rejected"));
    const cancelRate = n(kpi.requests) ? cancelled / n(kpi.requests) * 100 : 0;
    legend.innerHTML = `<button class="cp-flow-loss" type="button" data-drill="cancelled" style="--legend-color:${COLORS.danger}"><i></i><span>Rơi khỏi hành trình: <b>${fmt(cancelled)} mẫu đã hủy</b></span><strong>${cancelRate.toLocaleString("vi-VN", { maximumFractionDigits: 1 })}% mẫu duyệt</strong></button>`;
    [...flow.querySelectorAll("button"), ...legend.querySelectorAll("button")].forEach(button => button.addEventListener("click", () => openDrawer(button.dataset.drill, button.title || button.textContent.trim())));
  }

  function renderCompare(rows) {
    const byKind = new Map((Array.isArray(rows) ? rows : []).map(row => [row.sample_kind, row]));
    const free = byKind.get("free") || {}, refundable = byKind.get("refundable") || {};
    const rate = (row, key, denominator = "approved") => n(row[denominator]) ? Math.min(100, n(row[key]) / n(row[denominator]) * 100) : null;
    const metrics = [
      ["Hoàn thành", "completed", "approved"],
      ["Có video", "with_video", "approved"],
      ["Đúng hạn", "on_time", "on_time_eligible"],
    ];
    const target = $("cpCompare");
    if (!target) return;
    const kindCard = (kind, label, row, color) => {
      const skuCoverage = n(row.sent_requests) ? n(row.sent_requests_with_sku) / n(row.sent_requests) * 100 : 0;
      return `<button class="cp-kind-summary" type="button" data-kind="${kind}" style="--kind-color:${color}"><header><span>${escapeHtml(label)}</span><b>Xem KOC đã duyệt →</b></header><strong>${fmt(row.requests)} <small>mẫu</small></strong><div><span><b>${fmt(row.approved)}</b>KOC</span><span><b>${fmt(row.sent_spu)}</b>SPU đã gửi</span><span><b>${fmt(row.sent_sku)}</b>SKU đã gửi</span></div><small>SKU có dữ liệu ở ${skuCoverage.toLocaleString("vi-VN", { maximumFractionDigits: 0 })}% mẫu đã gửi</small></button>`;
    };
    const metricHtml = metrics.map(([label, key, denominator]) => {
      const freeRate = rate(free, key, denominator), refundRate = rate(refundable, key, denominator);
      const rowHtml = (kind, title, value, row, color) => `<div class="cp-kind-rate ${kind}"><span>${escapeHtml(title)}</span><div><i style="width:${value == null ? 0 : value.toFixed(1)}%;--rate-color:${color}"></i></div><strong>${value == null ? "—" : `${value.toFixed(1)}%`}</strong><small>${fmt(row[key])}/${fmt(row[denominator])}</small></div>`;
      return `<section class="cp-compare-metric"><h4>${escapeHtml(label)}</h4>${rowHtml("free", "Miễn phí", freeRate, free, COLORS.blue)}${rowHtml("refundable", "Hoàn tiền", refundRate, refundable, COLORS.pink)}${key === "on_time" && freeRate == null && refundRate == null ? '<p>Chưa đủ ngày hoàn/hạn để tính đúng hạn.</p>' : ""}</section>`;
    }).join("");
    target.innerHTML = `<div class="cp-kind-scope">${kindCard("free", "Hàng mẫu miễn phí", free, COLORS.blue)}${kindCard("refundable", "Hàng mẫu hoàn tiền", refundable, COLORS.pink)}</div><div class="cp-kind-metrics">${metricHtml}</div>`;
    target.querySelectorAll("[data-kind]").forEach(button => button.addEventListener("click", () => openDrawer("approved", `KOC đã duyệt · ${button.dataset.kind === "free" ? "Mẫu miễn phí" : "Mẫu hoàn tiền"}`, button.dataset.kind)));
  }

  function renderIssues(values) {
    const ranked = Object.entries(issueMeta).map(([key, meta]) => ({ key, ...meta, value: n(values[key]) }))
      .sort((a, b) => b.value - a.value);
    const target = $("cpIssues");
    if (!target) return;
    target.innerHTML = ranked.map((item, index) => `<button class="cp-issue" type="button" data-issue="${item.key}" style="--issue-color:${item.color}"><b class="cp-issue-rank">${index + 1}</b><span><strong>${escapeHtml(item.label)}</strong><small>${escapeHtml(item.hint)}</small></span><strong>${fmt(item.value)}</strong></button>`).join("");
    target.querySelectorAll("button").forEach(button => button.addEventListener("click", () => {
      const key = button.dataset.issue;
      openDrawer(key, issueMeta[key]?.label || "Chi tiết vấn đề");
    }));
  }

  function renderRefundFlow(rows) {
    const values = new Map((Array.isArray(rows) ? rows : []).map(row => [row.stage, n(row.creators)]));
    const items = [
      ["ready_to_ship", "Sẵn sàng vận chuyển"], ["shipped", "Đã vận chuyển"],
      ["in_progress", "Đang tiến hành"], ["refunded", "Đã hoàn tiền"], ["unrefunded", "Chưa hoàn tiền"],
    ];
    const target = $("cpRefundFlow");
    if (!target) return;
    target.innerHTML = items.map(([stage, label]) => `<button class="cp-refund-step ${stage === "unrefunded" ? "problem" : ""}" type="button" data-stage="${stage}"><span>${escapeHtml(label)}</span><strong>${fmt(values.get(stage))}</strong></button>`).join("");
    target.querySelectorAll("button").forEach(button => button.addEventListener("click", () => openDrawer(button.dataset.stage, stageLabels[button.dataset.stage] || "Chi tiết")));
  }

  function renderTrend(rows) {
    const svg = $("cpTrend");
    if (!svg) return;
    const days = periodDays();
    const byDay = new Map((Array.isArray(rows) ? rows : []).map(row => [row.day, row]));
    const points = [];
    const today = new Date();
    today.setHours(0, 0, 0, 0);
    for (let offset = days - 1; offset >= 0; offset -= 1) {
      const date = new Date(today.getTime() - offset * 86400000);
      const key = date.toISOString().slice(0, 10);
      points.push({ day: key, ...(byDay.get(key) || {}) });
    }
    const primaryMax = Math.max(1, ...points.map(point => n(point.recorded ?? point.approved)));
    const secondaryMax = Math.max(1, ...points.flatMap(point => [n(point.completed), n(point.cancelled)]));
    const left = 42, right = 704, top = 14, bottom = 206;
    const x = index => left + (points.length <= 1 ? 0 : index / (points.length - 1) * (right - left));
    const yPrimary = value => bottom - n(value) / primaryMax * (bottom - top);
    const ySecondary = value => bottom - n(value) / secondaryMax * (bottom - top);
    const chartPoints = (key, scale) => points.map((point, index) => [x(index), scale(point[key])]);
    const smooth = values => values.length ? values.slice(1).reduce((path, point, index) => {
      const previous = values[index], mid = (previous[0] + point[0]) / 2;
      return `${path} C ${mid.toFixed(1)} ${previous[1].toFixed(1)}, ${mid.toFixed(1)} ${point[1].toFixed(1)}, ${point[0].toFixed(1)} ${point[1].toFixed(1)}`;
    }, `M ${values[0][0].toFixed(1)} ${values[0][1].toFixed(1)}`) : "";
    const recordedPoints = points.map((point, index) => [x(index), yPrimary(point.recorded ?? point.approved)]);
    const completedPoints = chartPoints("completed", ySecondary), cancelledPoints = chartPoints("cancelled", ySecondary);
    const grid = [0, .25, .5, .75, 1].map(ratio => {
      const yy = bottom - ratio * (bottom - top);
      return `<line class="grid" x1="${left}" y1="${yy}" x2="${right}" y2="${yy}"></line><text class="axis-label" x="4" y="${yy + 4}">${Math.round(primaryMax * ratio)}</text><text class="axis-label axis-right" x="716" y="${yy + 4}" text-anchor="end">${Math.round(secondaryMax * ratio)}</text>`;
    }).join("");
    const labels = points.map((point, index) => index % Math.max(1, Math.ceil(points.length / 6)) === 0
      ? `<text class="axis-label" x="${x(index)}" y="228" text-anchor="middle">${point.day.slice(5).replace("-", "/")}</text>` : "").join("");
    const area = `${smooth(recordedPoints)} L ${right} ${bottom} L ${left} ${bottom} Z`;
    const hitWidth = (right - left) / Math.max(1, points.length - 1);
    const hover = points.map((point, index) => `<g class="hover-column"><rect class="hit" x="${x(index) - hitWidth / 2}" y="${top}" width="${hitWidth}" height="${bottom - top}"></rect><line x1="${x(index)}" y1="${top}" x2="${x(index)}" y2="${bottom}"></line><circle cx="${x(index)}" cy="${yPrimary(point.recorded ?? point.approved)}" r="4" class="approved"></circle><circle cx="${x(index)}" cy="${ySecondary(point.completed)}" r="4" class="completed"></circle><circle cx="${x(index)}" cy="${ySecondary(point.cancelled)}" r="4" class="cancelled"></circle><title>${point.day} · Cập nhật ${fmt(point.recorded ?? point.approved)} · Hoàn thành ${fmt(point.completed)} · Hủy ${fmt(point.cancelled)}</title></g>`).join("");
    svg.innerHTML = `<defs><linearGradient id="cpTrendArea" x1="0" y1="0" x2="0" y2="1"><stop offset="0" stop-color="${COLORS.purple}" stop-opacity=".28"></stop><stop offset="1" stop-color="${COLORS.purple}" stop-opacity="0"></stop></linearGradient></defs>${grid}${labels}<path class="trend-area" d="${area}"></path><path class="line approved" d="${smooth(recordedPoints)}"></path><path class="line completed" d="${smooth(completedPoints)}"></path><path class="line cancelled" d="${smooth(cancelledPoints)}"></path>${hover}`;
    const totals = points.reduce((sum, point) => ({ recorded: sum.recorded + n(point.recorded ?? point.approved), completed: sum.completed + n(point.completed), cancelled: sum.cancelled + n(point.cancelled) }), { recorded: 0, completed: 0, cancelled: 0 });
    $("cpTrendLegend").innerHTML = `<span class="approved">Mẫu cập nhật <b>${fmt(totals.recorded)}</b></span><span class="completed">Hoàn thành <b>${fmt(totals.completed)}</b></span><span class="cancelled">Đã hủy <b>${fmt(totals.cancelled)}</b></span><small>Trục trái: cập nhật · trục phải: hoàn thành/hủy</small>`;
  }

  function ensureDrawer() {
    if ($("cpDrawer")) return;
    const backdrop = document.createElement("div");
    backdrop.className = "cp-drawer-backdrop";
    backdrop.id = "cpDrawerBackdrop";
    const drawer = document.createElement("aside");
    drawer.className = "cp-drawer";
    drawer.id = "cpDrawer";
    drawer.setAttribute("role", "dialog");
    drawer.setAttribute("aria-modal", "true");
    drawer.innerHTML = `<div class="cp-drawer-head"><div><h2 id="cpDrawerTitle">Chi tiết</h2><p id="cpDrawerCount">Đang tải…</p></div><button class="cp-drawer-close" id="cpDrawerClose" type="button" aria-label="Đóng">×</button></div><div class="cp-drawer-tools"><input id="cpDrawerSearch" type="search" placeholder="Tên, ID KOC hoặc apply ID…"><select id="cpDrawerKind"><option value="">Cả hai loại mẫu</option><option value="free">Hàng mẫu miễn phí</option><option value="refundable">Hàng mẫu hoàn tiền</option></select><button class="secondary-button" id="cpPrepareReminder" type="button">Chuẩn bị nhắc</button></div><div class="cp-drawer-body" id="cpDrawerBody"></div>`;
    document.body.append(backdrop, drawer);
    const close = () => closeDrawer();
    backdrop.addEventListener("click", close);
    drawer.querySelector("#cpDrawerClose").addEventListener("click", close);
    let timer = 0;
    drawer.querySelector("#cpDrawerSearch").addEventListener("input", event => {
      clearTimeout(timer);
      timer = setTimeout(() => { ui.drawerKeyword = event.target.value.trim(); ui.drawerPage = 1; loadDrawer(); }, 280);
    });
    drawer.querySelector("#cpDrawerKind").addEventListener("change", event => { ui.drawerKind = event.target.value; ui.drawerPage = 1; loadDrawer(); });
    drawer.querySelector("#cpPrepareReminder").addEventListener("click", prepareReminder);
    document.addEventListener("keydown", event => { if (event.key === "Escape" && drawer.classList.contains("open")) closeDrawer(); });
  }

  function openDrawer(issue, label, kind = "") {
    ensureDrawer();
    ui.drawerIssue = issue || "approved";
    ui.drawerLabel = label || stageLabels[issue] || issueMeta[issue]?.label || "Chi tiết KOC";
    ui.drawerPage = 1;
    ui.drawerKeyword = "";
    ui.drawerKind = kind;
    $("cpDrawerTitle").textContent = ui.drawerLabel;
    $("cpDrawerSearch").value = "";
    $("cpDrawerKind").value = kind;
    $("cpDrawerBackdrop").classList.add("open");
    $("cpDrawer").classList.add("open");
    $("cpDrawerClose").focus();
    loadDrawer().catch(error => notifyError("Không tải được danh sách chi tiết", error));
  }

  function closeDrawer() {
    $("cpDrawerBackdrop")?.classList.remove("open");
    $("cpDrawer")?.classList.remove("open");
  }

  async function loadDrawer() {
    const body = $("cpDrawerBody");
    if (!body || !state?.shopId) return;
    body.innerHTML = '<div class="cp-drawer-empty">Đang tải danh sách KOC…</div>';
    const params = new URLSearchParams({
      shopId: String(state.shopId), region: String(state.region || "VN"), days: String(periodDays()),
      issue: ui.drawerIssue, page: String(ui.drawerPage), pageSize: "25",
    });
    if (ui.drawerKind) params.set("kind", ui.drawerKind);
    if (ui.drawerKeyword) params.set("keyword", ui.drawerKeyword);
    const data = await api(`/api/v1/collab-dashboard/creators?${params}`);
    renderDrawer(data || {});
  }

  function renderDrawer(data) {
    const body = $("cpDrawerBody");
    const records = Array.isArray(data.records) ? data.records : [];
    $("cpDrawerCount").textContent = `${fmt(data.total)} KOC · trang ${fmt(data.page || 1)}`;
    if (!records.length) { body.innerHTML = '<div class="cp-drawer-empty">Không có KOC phù hợp bộ lọc này.</div>'; return; }
    body.innerHTML = records.map(record => {
      const requests = Array.isArray(record.requests) ? record.requests : [];
      const avatar = mediaUrl(record.creator_avatar || "");
      return `<details class="cp-creator"><summary><img loading="lazy" src="${escapeHtml(avatar)}" alt="" onerror="this.style.visibility='hidden'"><span class="cp-creator-copy"><strong>${escapeHtml(record.creator_nickname || record.creator_handle || record.creator_key)}</strong><small>@${escapeHtml(record.creator_handle || "—")} · ID ${escapeHtml(record.creator_oec_id || record.creator_key)}</small></span><span class="cp-creator-metrics"><strong>${fmt(record.request_count)} yêu cầu</strong><small>${fmt(record.video_count)} video</small></span></summary><div class="cp-request-list">${requests.map(request => `<div class="cp-request"><img loading="lazy" src="${escapeHtml(mediaUrl(request.productImage || ""))}" alt="" onerror="this.style.visibility='hidden'"><span><strong title="${escapeHtml(request.productTitle || request.productId)}">${escapeHtml(request.productTitle || request.productId || "Sản phẩm")}</strong><small>${escapeHtml(request.kind === "refundable" ? "Hoàn tiền" : "Miễn phí")} · ${escapeHtml(stageLabels[request.stage] || request.stage)} · ${fmt(request.videoCount)} video</small></span>${Number(request.reviewStatus || 0) > 0 ? '<small>Đã đánh giá</small>' : (IS_EXTENSION_SURFACE ? `<button class="cp-review-btn" type="button" data-apply="${escapeHtml(request.applyId)}">Đánh giá</button>` : "")}</div>`).join("")}</div></details>`;
    }).join("") + `<div class="cp-drawer-pager"><button type="button" id="cpPrevPage" ${Number(data.page || 1) <= 1 ? "disabled" : ""}>‹</button><span>${fmt(data.page || 1)} / ${fmt(Math.max(1, Math.ceil(n(data.total) / n(data.pageSize || 25))))}</span><button type="button" id="cpNextPage" ${(n(data.page || 1) * n(data.pageSize || 25)) >= n(data.total) ? "disabled" : ""}>›</button></div>`;
    body.querySelectorAll(".cp-review-btn").forEach(button => button.addEventListener("click", () => openReview(button.dataset.apply)));
    $("cpPrevPage")?.addEventListener("click", () => { ui.drawerPage = Math.max(1, ui.drawerPage - 1); loadDrawer(); });
    $("cpNextPage")?.addEventListener("click", () => { ui.drawerPage += 1; loadDrawer(); });
  }

  async function prepareReminder() {
    const button = $("cpPrepareReminder");
    if (!button) return;
    button.disabled = true;
    try {
      const data = await api("/api/v1/collab-dashboard/reminders/prepare", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ shopId: state.shopId, region: state.region || "VN", issue: ui.drawerIssue, limit: 100 }),
      });
      const note = data?.sendEnabled
        ? "Danh sách đã sẵn sàng cho luồng nhắc qua TikTok."
        : "Chế độ gửi hàng loạt đang khóa an toàn; danh sách chỉ được chuẩn bị, chưa gửi tin nào.";
      showToast("Đã chuẩn bị danh sách nhắc", `${fmt(data?.count)} KOC. ${note}`, data?.sendEnabled ? "success" : "info", 10000);
    } catch (error) { notifyError("Không chuẩn bị được danh sách nhắc", error); }
    finally { button.disabled = false; }
  }

  function ensureReviewModal() {
    if ($("cpReviewModal")) return;
    const modal = document.createElement("div");
    modal.id = "cpReviewModal";
    modal.className = "cp-review-modal";
    modal.setAttribute("role", "dialog");
    modal.setAttribute("aria-modal", "true");
    modal.innerHTML = `<form class="cp-review-card" id="cpReviewForm"><h3>Đánh giá KOC</h3><p>Điểm sẽ được gửi lên TikTok và lưu lịch sử thao tác.</p><input type="hidden" name="applyId"><div class="cp-review-row"><label>Đánh giá chung</label><select name="overall">${scoreOptions()}</select></div><div class="cp-review-row"><label>Chất lượng nội dung</label><select name="content">${scoreOptions()}</select></div><div class="cp-review-row"><label>Thái độ cộng tác</label><select name="collaboration">${scoreOptions()}</select></div><label><input type="checkbox" name="anonymous"> Đánh giá ẩn danh</label><div class="cp-review-actions"><button class="secondary-button" type="button" id="cpReviewCancel">Hủy</button><button class="primary-button" type="submit">Xác nhận gửi</button></div></form>`;
    document.body.append(modal);
    $("cpReviewCancel").addEventListener("click", () => modal.classList.remove("open"));
    modal.addEventListener("click", event => { if (event.target === modal) modal.classList.remove("open"); });
    $("cpReviewForm").addEventListener("submit", submitReview);
  }
  function scoreOptions() { return [5, 4, 3, 2, 1].map(value => `<option value="${value}">${value}/5</option>`).join(""); }
  function openReview(applyId) {
    ensureReviewModal();
    $("cpReviewForm").elements.applyId.value = applyId;
    $("cpReviewModal").classList.add("open");
    $("cpReviewForm").elements.overall.focus();
  }
  async function submitReview(event) {
    event.preventDefault();
    const form = event.currentTarget;
    const submit = form.querySelector('[type="submit"]');
    if (!IS_EXTENSION_SURFACE) { showToast("Cần mở trong Extension", "Đánh giá TikTok chỉ chạy trong Extension đã đăng nhập đúng shop.", "warning"); return; }
    if (!confirm("Gửi đánh giá này lên TikTok? Thao tác không thể hoàn tác.")) return;
    submit.disabled = true;
    try {
      const response = await extensionMessage({
        type: "STONK_COLLAB_SAMPLE_REVIEW", shopId: state.shopId, region: state.region || "VN",
        applyId: form.elements.applyId.value, overallScore: form.elements.overall.value,
        contentQualityScore: form.elements.content.value, collaborationScore: form.elements.collaboration.value,
        anonymous: form.elements.anonymous.checked,
      }, { timeoutMs: 60000 });
      if (!response?.ok) throw new Error(response?.error || "TikTok không nhận đánh giá");
      $("cpReviewModal").classList.remove("open");
      showToast("Đã đánh giá", "Điểm KOC đã được lưu trên TikTok và lịch sử STONK.", "success");
      loadDrawer();
    } catch (error) { notifyError("Gửi đánh giá thất bại", error); }
    finally { submit.disabled = false; }
  }

  async function startSync({ scanVideos = false, syncMode = "incremental" } = {}) {
    if (!state?.shopId) { showToast("Chưa chọn shop", "Hãy chọn shop trước khi đồng bộ.", "warning"); return; }
    const buttons = [$("cpSyncData"), $("cpSyncFull"), $("cpSyncVideos")].filter(Boolean);
    buttons.forEach(button => { button.disabled = true; });
    const full = syncMode === "full";
    showProgress({ status: "running", mode: syncMode, label: full ? "Đang đối soát đầy đủ…" : scanVideos ? "Đang cập nhật nhanh và quét video đến hạn…" : "Đang cập nhật nhanh…", current: 0, total: 0 });
    if (!IS_EXTENSION_SURFACE) {
      try {
        const shopId = encodeURIComponent(String(state.shopId));
        // Cập nhật nhanh ưu tiên yêu cầu mẫu. Danh sách đợt cộng tác đã tự nạp
        // ở tab bên cạnh; chỉ lượt đối soát đầy đủ mới đọc lại toàn bộ lịch sử.
        let collaborations = { total: 0 };
        showProgress({ status: "running", mode: syncMode, label: "Đang phân loại yêu cầu mẫu mới nhất…", current: 0, total: 50 });
        const sampleRecords = await loadOfficialSampleDashboard();
        const sampleRows = sampleRecords.length;
        const approvedRows = sampleRecords.filter(row => !["pending_review", "rejected", "cancelled"].includes(String(row?.status || "")));
        const approvedCreators = new Set(approvedRows.map(row => String(row?.creatorOecId || row?.creatorHandle || "")).filter(Boolean));
        if (full) {
          collaborations = await api(`/api/v1/openapi/tiktok/shops/${shopId}/collaborations/search`, {
            method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({}),
          });
        }
        showProgress({ status: "completed", mode: syncMode, label: "Đã cập nhật từ TikTok Open API", current: sampleRows, total: sampleRows, updatedAt: Date.now() });
        showToast("Đã cập nhật", `${fmt(collaborations?.total || 0)} đợt cộng tác · ${fmt(approvedRows.length)} yêu cầu đã duyệt của ${fmt(approvedCreators.size)} KOC. Không cần mở tab TikTok.`, "success", 9000);
        // Open API đã ghi từng yêu cầu vào projection dùng chung. Đọc lại projection
        // để toàn bộ KPI/biểu đồ dùng cùng một nguồn bền vững, không chỉ 50 dòng vừa
        // trả về và không phụ thuộc TikTok ở lần mở tab kế tiếp.
        await loadDashboard({ refresh: true });
      } catch (error) {
        notifyError("Đồng bộ Open API thất bại", error);
      } finally {
        buttons.forEach(button => { button.disabled = false; });
      }
      return;
    }
    const traceId = newTraceId();
    try {
      traceLog(traceId, "dashboard:probe:start", {
        dashboardBuild: COLLAB_DASHBOARD_BUILD,
        protocol: COLLAB_CLIENT_PROTOCOL,
        shopId: String(state.shopId || ""),
        region: String(state.region || "VN"),
      });
      let runtime;
      try {
        runtime = await extensionMessage({
          type: "STONK_COLLAB_RUNTIME_PROBE",
          traceId,
          clientProtocol: COLLAB_CLIENT_PROTOCOL,
          dashboardBuild: COLLAB_DASHBOARD_BUILD,
          shopId: state.shopId,
          region: state.region || "VN",
        }, { timeoutMs: 10000 });
      } catch (probeError) {
        probeError.traceId = probeError.traceId || traceId;
        probeError.stage = probeError.stage || "dashboard:runtime-probe";
        probeError.message = `Không bắt tay được với service worker: ${probeError.message}`;
        throw probeError;
      }
      traceLog(traceId, "dashboard:probe:ok", runtime || {});
      if (runtime?.worker?.clientVersion !== COLLAB_DASHBOARD_BUILD || runtime?.worker?.protocol !== COLLAB_CLIENT_PROTOCOL) {
        const mismatch = new Error(`Dashboard ${COLLAB_DASHBOARD_BUILD} không cùng bản với service worker ${runtime?.worker?.clientVersion || "không rõ"}. Hãy đóng bảng, nạp lại extension BOOKING rồi tải lại tab TikTok.`);
        mismatch.code = "COLLAB_RUNTIME_MISMATCH";
        mismatch.stage = "dashboard:version-gate";
        mismatch.traceId = traceId;
        throw mismatch;
      }
      if (!runtime?.content?.ready) {
        const tabError = new Error(runtime?.content?.error || "Tab TikTok chưa phản hồi bộ thực thi của STONK. Hãy mở tab TikTok đúng shop rồi thử lại.");
        tabError.code = "COLLAB_CONTENT_NOT_READY";
        tabError.stage = "dashboard:content-probe";
        tabError.traceId = traceId;
        throw tabError;
      }
      if (runtime?.content?.contentVersion && runtime.content.contentVersion !== COLLAB_DASHBOARD_BUILD) {
        const contentMismatch = new Error(`Tab TikTok đang giữ content script ${runtime.content.contentVersion}, khác bản ${COLLAB_DASHBOARD_BUILD}. Hãy tải lại tab TikTok rồi thử lại.`);
        contentMismatch.code = "COLLAB_CONTENT_VERSION_MISMATCH";
        contentMismatch.stage = "dashboard:content-version-gate";
        contentMismatch.traceId = traceId;
        throw contentMismatch;
      }
      if (runtime?.content?.shopId && String(runtime.content.shopId) !== String(state.shopId)) {
        const shopMismatch = new Error(`Tab TikTok đang ở shop ${runtime.content.shopId}, còn STONK đang chọn shop ${state.shopId}. Hãy mở đúng shop rồi thử lại.`);
        shopMismatch.code = "COLLAB_SHOP_MISMATCH";
        shopMismatch.stage = "dashboard:shop-gate";
        shopMismatch.traceId = traceId;
        throw shopMismatch;
      }
      traceLog(traceId, "dashboard:sync:send", { scanVideos: scanVideos === true, syncMode });
      const result = await extensionMessage({
        type: "STONK_COLLAB_DASHBOARD_SYNC",
        traceId,
        clientProtocol: COLLAB_CLIENT_PROTOCOL,
        dashboardBuild: COLLAB_DASHBOARD_BUILD,
        shopId: state.shopId,
        region: state.region || "VN",
        scanVideos,
        syncMode,
        maxVideos: 500,
      }, { timeoutMs: 60 * 60 * 1000 });
      if (!result?.ok) throw new Error(result?.error || "Đồng bộ không hoàn tất");
      traceLog(traceId, "dashboard:sync:completed", { runId: result.runId, targetGroups: result.targetGroups, sampleRows: result.sampleRows, videoScanned: result.videoScanned });
      showToast(full ? "Đối soát đầy đủ hoàn tất" : "Cập nhật nhanh hoàn tất", `${fmt(result.targetGroups)} bản ghi cộng tác · ${fmt(result.sampleRows)} yêu cầu mẫu đã đọc · ${fmt(result.videoScanned)} lượt kiểm tra video.`, "success", 9000);
      await loadDashboard({ refresh: true });
    } catch (error) {
      error.traceId = error.traceId || traceId;
      error.stage = error.stage || "dashboard:sync";
      notifyError("Đồng bộ hiệu suất thất bại", error);
    }
    finally { buttons.forEach(button => { button.disabled = false; }); }
  }

  function showProgress(progress) {
    const box = $("cpProgress");
    if (!box) return;
    ui.syncProgress = progress || null;
    box.hidden = progress?.status === "completed" && Date.now() - Number(progress.updatedAt || 0) > 5000;
    if ($("cpProgressLabel")) $("cpProgressLabel").textContent = progress?.label || "Đang đồng bộ…";
    const current = n(progress?.current), total = n(progress?.total);
    if ($("cpProgressValue")) $("cpProgressValue").textContent = total ? `${fmt(current)}/${fmt(total)}` : current ? fmt(current) : "";
    if ($("cpProgressFill")) $("cpProgressFill").style.width = total ? `${Math.min(100, current / total * 100)}%` : progress?.status === "running" ? "18%" : "100%";
    renderSourceCharts(progress, ui.summary || {});
    scheduleLiveRefresh(progress);
  }

  document.addEventListener("click", event => {
    const collabNav = event.target.closest('.nav-item[data-view="collab"]');
    if (collabNav) setCampaignPanel(true);
    const kpi = event.target.closest("#cpKpis [data-drill], .cp-video-kpis [data-drill]");
    if (kpi) openDrawer(kpi.dataset.drill, kpi.querySelector("span")?.textContent || "Chi tiết");
  });
  $("cpPeriod")?.addEventListener("change", () => loadDashboard({ refresh: true }).catch(error => notifyError("Không đổi được khoảng thời gian", error)));
  $("cpSyncData")?.addEventListener("click", () => startSync({ syncMode: "incremental" }));
  $("cpSyncFull")?.addEventListener("click", () => startSync({ syncMode: "full" }));
  $("cpSyncVideos")?.addEventListener("click", () => startSync({ syncMode: "incremental", scanVideos: true }));
  const isExtSurface = typeof IS_EXTENSION_SURFACE !== "undefined" && IS_EXTENSION_SURFACE;
  if (isExtSurface && globalThis.chrome?.runtime?.onMessage) {
    chrome.runtime.onMessage.addListener(message => {
      if (message?.type === "STONK_COLLAB_SYNC_PROGRESS") {
        showProgress(message.progress || {});
        if (["completed", "failed"].includes(message.progress?.status)) {
          clearTimeout(ui.liveRefreshTimer);
          loadDashboard({ refresh: true }).catch(() => {});
        }
      }
    });
    chrome.storage?.local?.get(["stonk_collab_sync_progress"]).then(value => {
      if (value?.stonk_collab_sync_progress?.status === "running") showProgress(value.stonk_collab_sync_progress);
    }).catch(() => {});
  }
  globalThis.loadCollabPerformanceDashboard = loadDashboard;
})();
