# -*- coding: utf-8 -*-
"""舞台型ショートの「文字が被っている所」を探す（2026-11-07 エイイチ「文字が被ってるところがある」）
使い方: 作業フォルダで butai_kit.py --still を1回走らせて _block.html を作ってから
  python3 ../舞台型_共通/check_overlap.py 総尺秒
見るもの:
  1. モニターの中で、文字どうしが重なっている所（0.4秒以上続くものだけ。画面の切り替えの一瞬は数えない）
  2. モニターの中の文字が、エイイチの体の上 40%（頭と肩）にかかる所
     （エイイチは絵を後から重ねるのでページの中には無い。butai_kit.py --still が out/ei_rects.json に0.1秒ごとの位置を書く）
"""
import sys, os, json
from playwright.sync_api import sync_playwright

TOTAL = float(sys.argv[1])
EIR = {round(r[0], 1): r[1:] for r in json.load(open("out/ei_rects.json"))}
JS = r"""
(EI) => {
  const scr = document.querySelector('.scr');
  const out = [];
  const els = [...scr.querySelectorAll('*')].filter(e => [...e.childNodes].some(n => n.nodeType === 3 && n.textContent.trim()));
  const sr = scr.getBoundingClientRect();
  const effOp = (q) => { let o = 1; while (q && q !== scr) { const cs = getComputedStyle(q); o *= parseFloat(cs.opacity); if (cs.display === 'none' || cs.visibility === 'hidden') return 0; q = q.parentElement; } return o; };
  els.forEach((e, i) => {
    let op = 1, a = e;
    while (a && a !== scr) { const cs = getComputedStyle(a); op *= parseFloat(cs.opacity); if (cs.display === 'none' || cs.visibility === 'hidden') op = 0; a = a.parentElement; }
    if (op < 0.5) return;
    const rg = document.createRange(); let r = null;
    e.childNodes.forEach(n => { if (n.nodeType === 3 && n.textContent.trim()) { rg.selectNodeContents(n); for (const q of rg.getClientRects()) { r = r ? {l: Math.min(r.l, q.left), t: Math.min(r.t, q.top), r: Math.max(r.r, q.right), b: Math.max(r.b, q.bottom)} : {l: q.left, t: q.top, r: q.right, b: q.bottom}; } } });
    if (!r || r.r - r.l < 2) return;
    r = {l: Math.max(r.l, sr.left), t: Math.max(r.t, sr.top), r: Math.min(r.r, sr.right), b: Math.min(r.b, sr.bottom)};
    if (r.r <= r.l || r.b <= r.t) return;
    // 見えている点があるか（上に別の窓が重なって隠れていないか）
    let vis = 0;
    for (let gx = 1; gx < 8; gx++) for (let gy = 1; gy < 4; gy++) {
      const x = r.l + (r.r - r.l) * gx / 8, y = r.t + (r.b - r.t) * gy / 4;
      // いちばん上に見えているモニターの中の要素（舞台の外の飾りや、透明になった覆いは飛ばす）
      const h = document.elementsFromPoint(x, y).find(q => q !== scr && scr.contains(q) && effOp(q) > 0.05);
      if (h && (h === e || e.contains(h) || h.contains(e))) vis++;
    }
    out.push({id: i, txt: e.textContent.trim().slice(0, 14), r, vis, el: e});
  });
  const res = [];
  for (let i = 0; i < out.length; i++) {
    const A = out[i];
    if (A.vis && A.r.r > EI[0] + 6 && A.r.l < EI[2] - 6 && A.r.b > EI[1] + 6 && A.r.t < EI[3]) res.push(['頭', A.txt, Math.round(A.r.l), Math.round(A.r.t)]);
    for (let j = i + 1; j < out.length; j++) {
      const B = out[j];
      if (A.el.contains(B.el) || B.el.contains(A.el)) continue;
      const w = Math.min(A.r.r, B.r.r) - Math.max(A.r.l, B.r.l), h = Math.min(A.r.b, B.r.b) - Math.max(A.r.t, B.r.t);
      if (w > 4 && h > 4 && A.vis && B.vis) {   // 両方とも見えている所があるときだけ（上の窓で覆われた文字は数えない）
        const s = Math.min((A.r.r - A.r.l) * (A.r.b - A.r.t), (B.r.r - B.r.l) * (B.r.b - B.r.t));
        if (w * h > 0.04 * s) res.push(['重', A.txt + ' × ' + B.txt, Math.round(Math.max(A.r.l, B.r.l)), Math.round(Math.max(A.r.t, B.r.t))]);
      }
    }
  }
  return res;
}
"""
seen = {}
with sync_playwright() as p:
    br = p.chromium.launch(); pg = br.new_page(viewport={"width": 1080, "height": 1920})
    pg.goto("file://" + os.path.abspath("_block.html")); pg.evaluate("document.fonts.ready"); pg.wait_for_timeout(300)
    t = 0.0
    while t < TOTAL:
        pg.evaluate(f"window.setT({t:.2f})")
        for kind, what, x, y in pg.evaluate(JS, EIR.get(round(t, 1), [0, 9999, 0, 0])):
            k = (kind, what)
            seen.setdefault(k, []).append(round(t, 1))
        t += 0.1
    br.close()
bad = 0
for (kind, what), ts in seen.items():
    if len(ts) >= (2 if kind == '頭' else 4):
        bad += 1
        print(f"{'文字どうし' if kind == '重' else 'エイイチの頭'}: {what}  {ts[0]}〜{ts[-1]}秒（{len(ts) / 10:.1f}秒）")
print("被り", bad, "件")
