# -*- coding: utf-8 -*-
"""Read a returned translation workbook back into the dictionaries.

    python scripts/i18n-import.py <returned-file.xlsx>
    node scripts/build-pages.mjs          # then rebuild to apply

Counterpart of scripts/i18n-export.py. Any returned file works, old or new —
matching is by the ID column for chrome rows and by the (cleaned) English text
for body rows, so column order, row order, and which handoff file it was do not
matter; extra columns the translator added are ignored.

For every row she FILLED IN (Japanese text present):
  chrome rows   update src/i18n/dictionaries/ja.json in place
  body rows     update the pair where it lives (harvested-body / drafted-body);
                a new translation is appended to drafted-body with its raw
                source form recovered from the built /ja pages
and the row is recorded in src/i18n/translator-done.json, so it stops
appearing in future TODO files (see i18n-export.py).

A row left EMPTY is simply not done yet — it is skipped here and comes back in
the next TODO file. To deliberately keep a string English she writes
"keep English" in the Notes column: that records the row as done without a
translation (and removes any existing pair, so the string renders English).

Nothing is guessed: a row whose English no longer matches anything (copy was
rewritten since export) is reported, not silently imported.
"""
import io, json, re, sys, html as H, os, collections
from openpyxl import load_workbook

sys.stdout.reconfigure(encoding="utf-8")
if len(sys.argv) < 2:
    sys.exit("usage: python scripts/i18n-import.py <workbook.xlsx>")

jp = re.compile(r"[぀-ヿ一-鿿]")
clean = lambda s: re.sub(r"\s+", " ", H.unescape(str(s)).replace(" ", " ")).strip()

wb = load_workbook(sys.argv[1], data_only=True)
ws = wb["Translations"]
head = [str(c.value or "") for c in ws[1]]
col = {name: i for i, name in enumerate(head)}
def pick(row, key_start):
    for name, i in col.items():
        if name.lower().startswith(key_start):
            return row[i] if i < len(row) else None
    return None

en = json.load(io.open("src/i18n/dictionaries/en.json", encoding="utf-8-sig"))
ja_path = "src/i18n/dictionaries/ja.json"
ja = json.load(io.open(ja_path, encoding="utf-8-sig"), object_pairs_hook=collections.OrderedDict)
files = {
    "harvested": ("src/i18n/harvested-body.ja.json",
                  json.load(io.open("src/i18n/harvested-body.ja.json", encoding="utf-8"),
                            object_pairs_hook=collections.OrderedDict)),
    "drafted": ("src/i18n/drafted-body.ja.json",
                json.load(io.open("src/i18n/drafted-body.ja.json", encoding="utf-8"),
                          object_pairs_hook=collections.OrderedDict)),
}
DONE_PATH = "src/i18n/translator-done.json"
done = {"_note": "Rows the translator has returned; the export skips them. "
                 "Written by scripts/i18n-import.py — do not edit by hand.",
        "chrome": {}, "body": []}
if os.path.exists(DONE_PATH):
    done = json.load(io.open(DONE_PATH, encoding="utf-8"))
done_body = set(done.get("body", []))
done_chrome = done.setdefault("chrome", {})

# cleaned EN -> (which file, raw key)
by_clean = {}
for name, (_, d) in files.items():
    for raw in d["pairs"]:
        by_clean.setdefault(clean(raw), (name, raw))

# cleaned EN -> raw form, recovered from the built ja pages (for new rows)
raws = {}
for root, dirs, fs in os.walk("public/landing/ja"):
    for f in fs:
        if f != "index.html":
            continue
        h = io.open(os.path.join(root, f), encoding="utf-8", errors="ignore").read()
        body = re.sub(r"(?is)<(script|style|svg|noscript)[^>]*>.*?</\1>", " ", h)
        for m in re.finditer(r">([^<>]{4,2000})<", body):
            raws.setdefault(clean(m.group(1)), m.group(1))

updated = added = kept_english = skipped = 0
unmatched, notes = [], []
for row in ws.iter_rows(min_row=2, values_only=True):
    rid = str(pick(row, "id") or "").strip()
    e = clean(pick(row, "english") or "")
    j = str(pick(row, "japanese") or "").strip()
    if j.lower() == "none": j = ""
    note = str(pick(row, "notes") or "").strip()
    if note.lower() == "none": note = ""
    if not rid or not e:
        continue
    keep_en = bool(re.search(r"keep\s+english", note, re.I))
    if note and not keep_en:
        notes.append(f"{e[:60]}  —  {note[:120]}")
    if not j and not keep_en:                           # not done yet, comes back next time
        skipped += 1
        continue
    if rid != "body":                                   # chrome: nav.x / footer.x
        grp, _, key = rid.partition(".")
        if grp in ("nav", "footer") and key in en.get(grp, {}):
            if clean(en[grp][key]) != e:                # English rewritten since this export —
                unmatched.append(f"{rid} (English changed: {e[:50]})")
                continue                                # her translation is of the old copy
            want = e if keep_en else j
            if clean(ja[grp].get(key, "")) != clean(want):
                ja[grp][key] = want
                updated += 0 if keep_en else 1
            kept_english += 1 if keep_en else 0
            done_chrome[rid] = e
        else:
            unmatched.append(rid)
        continue
    hit = by_clean.get(e)
    if keep_en:
        if hit:                                         # deliberately English: drop the pair
            name, raw = hit
            del files[name][1]["pairs"][raw]
        kept_english += 1
        done_body.add(e)
    elif hit:
        name, raw = hit
        d = files[name][1]
        if d["pairs"][raw] != j:
            d["pairs"][raw] = j; updated += 1
        done_body.add(e)
    else:                                               # newly translated row
        raw = raws.get(e)
        if raw is None:
            unmatched.append(e[:70]); continue
        files["drafted"][1]["pairs"][raw] = j; added += 1
        done_body.add(e)

done["body"] = sorted(done_body)
io.open(DONE_PATH, "w", encoding="utf-8").write(json.dumps(done, ensure_ascii=False, indent=1) + "\n")
io.open(ja_path, "w", encoding="utf-8").write(json.dumps(ja, ensure_ascii=False, indent=2) + "\n")
for path, d in files.values():
    io.open(path, "w", encoding="utf-8").write(json.dumps(d, ensure_ascii=False, indent=1) + "\n")

print(f"updated {updated} · added {added} · kept-English {kept_english} · left empty (not done yet) {skipped}")
print(f"done-list now {len(done_body)} body strings + {len(done_chrome)} chrome keys ({DONE_PATH})")
if notes:
    print(f"\nher Notes ({len(notes)}):")
    for n in notes[:30]:
        print("  ", n)
if unmatched:
    print(f"\n{len(unmatched)} rows matched nothing (copy rewritten since export?) — NOT imported:")
    for u in unmatched[:20]:
        print("  ", u)
print("\nnow rebuild:  node scripts/build-pages.mjs")
