"""Which titles does AniList's phone layout cut off?

Opens AniList search on a 390 px phone viewport, takes one real result card title element (12px Overpass,
2-line clamp), puts every English title from data/clean/anime.csv into a copy of it and checks whether it
overflows. Also measures how many characters fit on one full-width phone line at AniList's 16px body font.
Writes data/clean/truncation.csv (id, cut_card, card_visible_chars).
"""
import json
from pathlib import Path

import pandas as pd
from playwright.sync_api import sync_playwright

ROOT = Path(__file__).resolve().parent.parent
CLEAN = ROOT / "data" / "clean"

JS = """(titles) => {
  const src = document.querySelector('.media-card > a.title');
  const probe = src.cloneNode(false);
  probe.removeAttribute('href');
  src.parentElement.appendChild(probe);
  const out = [];
  for (const t of titles) {
    probe.textContent = t;
    const cut = probe.scrollHeight > probe.clientHeight + 1;
    let visible = t.length;
    if (cut) {  // binary search for the longest prefix that still fits
      let lo = 0, hi = t.length;
      while (lo < hi) { const mid = (lo + hi + 1) >> 1; probe.textContent = t.slice(0, mid);
        if (probe.scrollHeight > probe.clientHeight + 1) hi = mid - 1; else lo = mid; }
      visible = lo;
    }
    out.push([cut, visible]);
  }
  const cs = getComputedStyle(src);
  return {rows: out, style: {width: src.clientWidth, font: cs.fontSize + ' ' + cs.fontFamily.split(',')[0], clamp: cs.webkitLineClamp}};
}"""


def main():
    a = pd.read_csv(CLEAN / "anime.csv")
    a = a[a.has_english]
    with sync_playwright() as p:
        b = p.chromium.launch(channel="msedge")
        pg = b.new_page(viewport={"width": 390, "height": 844}, device_scale_factor=3, is_mobile=True, has_touch=True)
        pg.goto("https://anilist.co/search/anime?search=reincarnated", wait_until="domcontentloaded")
        pg.wait_for_selector(".media-card > a.title", timeout=60000)
        pg.wait_for_timeout(2500)
        res = pg.evaluate(JS, a.title_english.tolist())
        line = pg.evaluate("""() => { const d = document.createElement('div');
            d.style.cssText = 'position:absolute;white-space:nowrap;font:16px Overpass;visibility:hidden';
            document.body.appendChild(d); const s = 'abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
            d.textContent = s.repeat(4); return {avg_char_px: d.offsetWidth / d.textContent.length, usable_px: window.innerWidth - 32}; }""")
        b.close()
    t = pd.DataFrame(res["rows"], columns=["cut_card", "card_visible_chars"])
    t.insert(0, "id", a.id.values)
    t.to_csv(CLEAN / "truncation.csv", index=False)
    meta = {"card_style": res["style"], "phone_line": line, "chars_per_phone_line": round(line["usable_px"] / line["avg_char_px"], 1)}
    (CLEAN / "truncation_meta.json").write_text(json.dumps(meta, indent=1), encoding="utf-8")
    print(meta, "cut:", round(t.cut_card.mean() * 100, 1), "%")


if __name__ == "__main__":
    main()
