#!/usr/bin/env python3
"""
Extract gettext strings from plugin PHP (__, esc_html__, esc_attr__, _n) for domain
etchenet-reviews-for-google-business and write languages/etchenet-reviews-for-google-business.pot
"""
from __future__ import annotations

import re
from datetime import datetime, timezone
from pathlib import Path

DOMAIN = "etchenet-reviews-for-google-business"
ROOT = Path(__file__).resolve().parents[1]
FILES = [
    ROOT / "g-reviews-pro.php",
    ROOT / "includes" / "class-egr-admin.php",
    ROOT / "includes" / "class-egr-badge.php",
    ROOT / "includes" / "class-egr-shortcode.php",
    ROOT / "includes" / "class-egr-import.php",
    ROOT / "templates" / "slider-template.php",
]
OUT = ROOT / "languages" / f"{DOMAIN}.pot"

FUNCS2 = ("__", "esc_html__", "esc_attr__", "_e", "esc_html_e", "esc_attr_e")


def rel(p: Path) -> str:
    try:
        return str(p.relative_to(ROOT)).replace("\\", "/")
    except ValueError:
        return p.name


def read_string(code: str, i: int) -> tuple[str, int] | None:
    """Parse PHP single- or double-quoted string starting at code[i]. Returns (value, index_after_closing_quote)."""
    if i >= len(code):
        return None
    q = code[i]
    if q not in "'\"":
        return None
    i += 1
    out: list[str] = []
    while i < len(code):
        c = code[i]
        if c == "\\" and i + 1 < len(code):
            n = code[i + 1]
            if q == '"':
                # double-quoted PHP escapes
                esc = {
                    "n": "\n",
                    "r": "\r",
                    "t": "\t",
                    "$": "$",
                    '"': '"',
                    "\\": "\\",
                }
                out.append(esc.get(n, n))
                i += 2
                continue
            if q == "'":
                if n in ("\\", "'"):
                    out.append(n)
                    i += 2
                    continue
                out.append(n)
                i += 2
                continue
        if c == q:
            return "".join(out), i + 1
        out.append(c)
        i += 1
    return None


def skip_ws(code: str, i: int) -> int:
    while i < len(code) and code[i] in " \t\n\r":
        i += 1
    return i


def find_line(code: str, pos: int) -> int:
    return code.count("\n", 0, pos) + 1


def scan_file(path: Path) -> list[tuple[str, str, str | None, int]]:
    """List of (msgid, msgid_plural_or_None, ref_file:line, kind)."""
    code = path.read_text(encoding="utf-8")
    rpath = rel(path)
    results: list[tuple[str, str, str | None, int]] = []

    for m in re.finditer(r"\b(__|esc_html__|esc_attr__|_e|esc_html_e|esc_attr_e|_n)\s*\(", code):
        fn = m.group(1)
        i = m.end()
        i = skip_ws(code, i)
        s1 = read_string(code, i)
        if not s1:
            continue
        val1, i = s1
        i = skip_ws(code, i)
        if i >= len(code) or code[i] != ",":
            continue
        i += 1
        i = skip_ws(code, i)

        if fn == "_n":
            s2 = read_string(code, i)
            if not s2:
                continue
            val2, i = s2
            i = skip_ws(code, i)
            if i >= len(code) or code[i] != ",":
                continue
            i += 1
            i = skip_ws(code, i)
            depth = 0
            while i < len(code):
                ch = code[i]
                if ch == "(":
                    depth += 1
                elif ch == ")":
                    if depth == 0:
                        break
                    depth -= 1
                elif ch == "," and depth == 0:
                    break
                i += 1
            if i >= len(code) or code[i] != ",":
                continue
            i += 1
            i = skip_ws(code, i)
            sdom = read_string(code, i)
            if not sdom:
                continue
            dom, _ = sdom
            if dom != DOMAIN:
                continue
            line = find_line(code, m.start())
            results.append((val1, val2, f"{rpath}:{line}", "_n"))
        else:
            sdom = read_string(code, i)
            if not sdom:
                continue
            dom, _ = sdom
            if dom != DOMAIN:
                continue
            line = find_line(code, m.start())
            results.append((val1, "", f"{rpath}:{line}", fn))

    return results


def pot_escape(s: str) -> str:
    return s.replace("\\", "\\\\").replace('"', '\\"')


def format_msgid(label: str, s: str) -> list[str]:
    if s == "":
        return [f'{label} ""']
    if "\n" in s or len(s) > 70:
        lines = s.split("\n")
        out = [f'{label} ""']
        for k, line in enumerate(lines):
            suf = "\\n" if k < len(lines) - 1 else ""
            out.append(f'"{pot_escape(line)}{suf}"')
        return out
    return [f'{label} "{pot_escape(s)}"']


def main() -> None:
    refs: dict[str, list[str]] = {}
    plurals: dict[str, tuple[str, str, list[str]]] = {}

    for path in FILES:
        if not path.exists():
            continue
        for msgid, msgid_plural, ref, kind in scan_file(path):
            if kind == "_n":
                key = "\x00PLURAL\x00" + msgid + "\x00" + msgid_plural
                if key not in plurals:
                    plurals[key] = (msgid, msgid_plural, [])
                if ref not in plurals[key][2]:
                    plurals[key][2].append(ref)
            else:
                if msgid not in refs:
                    refs[msgid] = []
                if ref not in refs[msgid]:
                    refs[msgid].append(ref)

    date = datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M+0000")
    lines: list[str] = [
        "# Copyright (C) " + datetime.now(timezone.utc).strftime("%Y") + " Etchenet",
        "# This file is distributed under the same license as the plugin.",
        'msgid ""',
        'msgstr ""',
        '"Project-Id-Version: Etchenet Reviews for Google Business\\n"',
        '"Report-Msgid-Bugs-To: \\n"',
        f'"POT-Creation-Date: {date}\\n"',
        '"MIME-Version: 1.0\\n"',
        '"Content-Type: text/plain; charset=UTF-8\\n"',
        '"Content-Transfer-Encoding: 8bit\\n"',
        f'"X-Domain: {DOMAIN}\\n"',
        "",
    ]

    keys = sorted(refs.keys(), key=lambda x: x.replace("\n", " "))
    pkeys = sorted(plurals.keys())

    for k in keys:
        for r in sorted(refs[k]):
            lines.append(f"#: {r}")
        lines.extend(format_msgid("msgid", k))
        lines.append('msgstr ""')
        lines.append("")

    for pk in pkeys:
        sing, plural, rlist = plurals[pk]
        for r in sorted(rlist):
            lines.append(f"#: {r}")
        lines.extend(format_msgid("msgid", sing))
        lines.extend(format_msgid("msgid_plural", plural))
        lines.append('msgstr[0] ""')
        lines.append('msgstr[1] ""')
        lines.append("")

    OUT.parent.mkdir(parents=True, exist_ok=True)
    OUT.write_text("\n".join(lines), encoding="utf-8")
    print(f"Wrote {OUT} ({len(keys)} singular + {len(pkeys)} plural)")


if __name__ == "__main__":
    main()
