import { forwardRef, useEffect, useImperativeHandle, useRef, useState } from "react";

// Bảng tổ hợp ẢO HOÁ (chỉ vẽ dòng đang thấy) + bộ lọc bằng NÚT nối chuỗi —
// mirror tool video_cook (ui/combo_model.py + ui/tab2_output.py).
//   Cột: STT | "tên + tên + tên" | [🎵 Source] | ✓
//   Lọc: Đặt lại / Chọn hết / Bỏ hết / Lọc ngẫu nhiên % / Lọc tương đồng %
//        + "Ưu tiên khúc khác hoàn toàn". Tất cả chạy trên tập ĐANG CHỌN.
// Trạng thái tick giữ trong Uint8Array (chịu được vài trăm nghìn dòng, thao tác
// hàng loạt chỉ vài ms). Lọc tương đồng đẩy sang Web Worker để UI không đơ.

const ROW_H = 30;
const VIEW_H = 384;
const RANK_BLOCK = 8192;
const JOIN = "  +  ";

const ComboTable = forwardRef(function ComboTable(
  { sequences, clipNames, nSeg, sources = [], maxRender = 10000, onCount }, ref) {

  const n = sequences.length;
  const checkedRef = useRef(new Uint8Array(0));
  const rankRef = useRef(null);                 // prefix-sum số dòng chọn / block
  const workerRef = useRef(null);
  const [checkedCount, setCheckedCount] = useState(0);
  const [, force] = useState(0);
  const bump = () => force((x) => x + 1);
  const [scrollTop, setScrollTop] = useState(0);
  const [randPct, setRandPct] = useState(50);
  const [simPct, setSimPct] = useState(50);
  const [prio, setPrio] = useState([]);         // bool theo từng khúc
  const [filtering, setFiltering] = useState(null);  // {msg,pct} | null
  const [status, setStatus] = useState("");

  // Nạp bộ dữ liệu mới -> tick hết, dọn mọi thứ.
  useEffect(() => {
    const buf = new Uint8Array(n);
    buf.fill(1);
    checkedRef.current = buf;
    rankRef.current = null;
    setCheckedCount(n);
    setScrollTop(0);
    setPrio(Array.from({ length: nSeg }, () => false));
    setStatus("");
    bump();
    // eslint-disable-next-line
  }, [sequences, clipNames, nSeg]);

  // Worker lọc tương đồng (tạo 1 lần).
  useEffect(() => {
    const w = new Worker(new URL("../workers/simFilter.js", import.meta.url), { type: "module" });
    workerRef.current = w;
    return () => { try { w.terminate(); } catch { /* */ } };
  }, []);

  useEffect(() => { onCount && onCount(checkedCount); }, [checkedCount, onCount]);

  useImperativeHandle(ref, () => ({
    getSelected() {
      const c = checkedRef.current;
      const out = [];
      for (let i = 0; i < c.length; i++) if (c[i]) out.push(sequences[i]);
      return out;
    },
    selectedCount: () => checkedCount,
  }), [sequences, checkedCount]);

  // ── thao tác tick ──────────────────────────────────────────────────────
  const invalidate = () => { rankRef.current = null; };
  const recount = () => {
    let s = 0; const c = checkedRef.current;
    for (let i = 0; i < c.length; i++) s += c[i];
    setCheckedCount(s);
  };
  const toggle = (i) => {
    const c = checkedRef.current;
    c[i] ^= 1;
    setCheckedCount((v) => v + (c[i] ? 1 : -1));
    invalidate(); bump();
  };
  const setAll = (v) => {
    checkedRef.current.fill(v ? 1 : 0);
    setCheckedCount(v ? n : 0);
    invalidate(); bump();
    setStatus(v ? `↺ Đã chọn tất cả ${n} tổ hợp` : "Đã bỏ chọn hết");
  };
  const setRows = (rows) => {
    const buf = new Uint8Array(n);
    for (const r of rows) if (r >= 0 && r < n) buf[r] = 1;
    checkedRef.current = buf;
    invalidate(); bump(); recount();
  };
  const checkedRows = () => {
    const c = checkedRef.current; const out = [];
    for (let i = 0; i < c.length; i++) if (c[i]) out.push(i);
    return out;
  };

  // ── cột 🎵 Source: xoay vòng theo THỨ HẠNG trong các dòng ĐANG CHỌN ───────
  const buildRank = () => {
    const c = checkedRef.current;
    const blocks = Math.ceil(n / RANK_BLOCK) + 1;
    const idx = new Int32Array(blocks);
    let total = 0;
    for (let b = 0; b < blocks - 1; b++) {
      idx[b] = total;
      const end = Math.min((b + 1) * RANK_BLOCK, n);
      for (let i = b * RANK_BLOCK; i < end; i++) total += c[i];
    }
    idx[blocks - 1] = total;
    rankRef.current = idx;
    return idx;
  };
  const sourceFor = (row) => {
    if (!sources.length) return null;
    const idx = rankRef.current || buildRank();
    const block = (row / RANK_BLOCK) | 0;
    let rank = idx[block];
    const c = checkedRef.current;
    for (let i = block * RANK_BLOCK; i < row; i++) rank += c[i];
    return sources[rank % sources.length];
  };

  // ── bộ lọc ───────────────────────────────────────────────────────────────
  const reset = () => setAll(true);

  const randomFilter = () => {
    const pool = checkedRows();
    if (!pool.length) { setStatus("Chưa chọn tổ hợp nào để lọc."); return; }
    const keepCount = Math.max(1, Math.round(pool.length * randPct / 100));
    // Fisher–Yates một phần -> lấy keepCount phần tử ngẫu nhiên, không lệch.
    for (let i = 0; i < keepCount; i++) {
      const j = i + Math.floor(Math.random() * (pool.length - i));
      const t = pool[i]; pool[i] = pool[j]; pool[j] = t;
    }
    setRows(pool.slice(0, keepCount));
    setStatus(`🎲 Giữ ${keepCount}/${pool.length} ngẫu nhiên (${randPct}% của tập đang chọn)`);
  };

  const similarityFilter = () => {
    const pool = checkedRows();
    if (!pool.length) { setStatus("Chưa chọn tổ hợp nào để lọc."); return; }
    const maxSame = Math.floor(simPct / 100 * nSeg + 1e-9);
    const priorityCols = prio.map((p, i) => (p ? i : -1)).filter((i) => i >= 0);
    // dựng mảng phẳng các hàng đang chọn -> chuyển thẳng sang worker (transferable)
    const flat = new Int32Array(pool.length * nSeg);
    for (let k = 0; k < pool.length; k++) {
      const seq = sequences[pool[k]]; const base = k * nSeg;
      for (let j = 0; j < nSeg; j++) flat[base + j] = seq[j];
    }
    setFiltering({ msg: `🔍 Đang lọc ${pool.length} tổ hợp…`, pct: 0 });
    const w = workerRef.current;
    w.onmessage = (e) => {
      const d = e.data;
      if (d.type === "progress") {
        setFiltering({ msg: `🔍 Đang lọc tương đồng… ${Math.round(d.done / d.total * 100)}%`, pct: Math.round(d.done / d.total * 100) });
        return;
      }
      // done
      const keep = d.keep;
      const keptRows = [];
      for (let k = 0; k < pool.length; k++) if (keep[k]) keptRows.push(pool[k]);
      setRows(keptRows);
      setFiltering(null);
      setStatus(`🔍 Xong! Còn ${keptRows.length}/${pool.length} (loại ${pool.length - keptRows.length} tổ hợp tương đồng)`);
    };
    w.postMessage({ flat, nSeg, maxSame, priorityCols }, [flat.buffer]);
  };

  // ── ảo hoá ────────────────────────────────────────────────────────────────
  const start = Math.max(0, ((scrollTop / ROW_H) | 0) - 6);
  const visN = Math.ceil(VIEW_H / ROW_H) + 12;
  const end = Math.min(n, start + visN);
  const rows = [];
  const c = checkedRef.current;
  for (let i = start; i < end; i++) {
    const on = !!c[i];
    const names = sequences[i].map((id) => clipNames[id] || String(id)).join(JOIN);
    const src = sourceFor(i);
    rows.push(
      <div key={i} onClick={() => toggle(i)}
           style={{ display: "flex", alignItems: "center", height: ROW_H, cursor: "pointer",
                    background: i % 2 ? "var(--white)" : "var(--cream)", opacity: on ? 1 : 0.4,
                    borderBottom: "1px solid var(--line)", fontSize: 12 }}>
        <div style={{ width: 56, textAlign: "center", color: "var(--orange-700)", flexShrink: 0 }}>{i + 1}</div>
        <div style={{ flex: 1, minWidth: 0, whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", paddingRight: 8 }}
             title={sequences[i].map((id) => clipNames[id] || String(id)).join("\n")}>{names}</div>
        {src != null && (
          <div style={{ width: 150, flexShrink: 0, color: "#0a8f3c", whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis", paddingRight: 8 }} title={src}>🎵 {src}</div>
        )}
        <div style={{ width: 46, textAlign: "center", flexShrink: 0 }}>
          <input type="checkbox" checked={on} readOnly tabIndex={-1} style={{ pointerEvents: "none" }} />
        </div>
      </div>
    );
  }

  const over = checkedCount > maxRender;

  return (
    <div>
      {/* thanh công cụ */}
      <div className="flex center gap8" style={{ flexWrap: "wrap", marginBottom: 8 }}>
        <button className="btn sm" onClick={reset} title="Chọn lại TẤT CẢ — huỷ mọi bộ lọc đã áp">↺ Đặt lại</button>
        <button className="btn sm" onClick={() => setAll(true)}>☑ Tất cả</button>
        <button className="btn sm ghost" onClick={() => setAll(false)}>☐ Bỏ hết</button>
        <span style={{ width: 1, height: 22, background: "var(--line)" }} />
        <span className="small muted">Ngẫu nhiên</span>
        <input type="number" min="1" max="99" value={randPct} onChange={(e) => setRandPct(Math.max(1, Math.min(99, +e.target.value || 1)))} style={{ width: 60 }} />
        <button className="btn sm" onClick={randomFilter} disabled={!!filtering} title="Giữ lại X% video ngẫu nhiên (trong tập đang chọn)">Lọc ngẫu nhiên</button>
        <span style={{ width: 1, height: 22, background: "var(--line)" }} />
        <span className="small muted">Tương đồng</span>
        <input type="number" min="0" max="100" value={simPct} onChange={(e) => setSimPct(Math.max(0, Math.min(100, +e.target.value || 0)))} style={{ width: 60 }} />
        <button className="btn sm" onClick={similarityFilter} disabled={!!filtering}
                title="Chỉ giữ combo có mức tương đồng ≤ ngưỡng. 0% = khác nhau HOÀN TOÀN; 100% = giữ tất cả.">
          {filtering ? "⏳ Đang lọc…" : "Lọc tương đồng"}
        </button>
        <span className="small" style={{ marginLeft: "auto", color: "var(--orange-700)", fontWeight: 600 }}>
          Đã chọn: {checkedCount.toLocaleString()} / {n.toLocaleString()}
        </span>
      </div>

      {/* ưu tiên khúc khác hoàn toàn */}
      {nSeg > 0 && (
        <div className="flex center gap8" style={{ flexWrap: "wrap", marginBottom: 8 }}>
          <span className="small muted" title="Các khúc được tick sẽ bị ép KHÁC NHAU HOÀN TOÀN giữa các video giữ lại (kết hợp với ngưỡng % tương đồng).">Ưu tiên khác hoàn toàn ở khúc:</span>
          {prio.map((p, i) => (
            <label key={i} className="small" style={{ display: "inline-flex", alignItems: "center", gap: 4, cursor: "pointer" }}>
              <input type="checkbox" checked={p} onChange={() => setPrio((cur) => cur.map((v, j) => (j === i ? !v : v)))} />
              Khúc {i + 1}
            </label>
          ))}
        </div>
      )}

      {/* tiêu đề cột */}
      <div style={{ display: "flex", alignItems: "center", height: 26, fontSize: 11, fontWeight: 700, color: "var(--muted)", borderBottom: "2px solid var(--line)" }}>
        <div style={{ width: 56, textAlign: "center", flexShrink: 0 }}>STT</div>
        <div style={{ flex: 1 }}>Tổ hợp video</div>
        {sources.length > 0 && <div style={{ width: 150, flexShrink: 0 }}>🎵 Source</div>}
        <div style={{ width: 46, textAlign: "center", flexShrink: 0 }}>✓</div>
      </div>

      {/* danh sách ảo hoá */}
      <div onScroll={(e) => setScrollTop(e.currentTarget.scrollTop)}
           style={{ height: VIEW_H, overflow: "auto", border: "1px solid var(--line)", borderTop: "none" }}>
        <div style={{ height: n * ROW_H, position: "relative" }}>
          <div style={{ position: "absolute", top: start * ROW_H, left: 0, right: 0 }}>{rows}</div>
        </div>
      </div>

      {filtering && (
        <div className="small" style={{ color: "#b45309", marginTop: 6 }}>{filtering.msg}</div>
      )}
      {!filtering && status && (
        <div className="small muted" style={{ marginTop: 6 }}>{status}</div>
      )}
      {over && (
        <p className="small mt8" style={{ color: "var(--orange-700)" }}>
          ⚠ Đang chọn {checkedCount.toLocaleString()} biến thể — chỉ render tối đa {maxRender.toLocaleString()} video/lần, phần dư sẽ bị bỏ.
        </p>
      )}
    </div>
  );
});

export default ComboTable;
