#!/usr/bin/env python3
"""Look up the redesign copy of each given key, one language map per key.

The primary source is the Suggested/<Key>.json file of each key, found in a
resources checkout or a snapshot of it. A key missing there can still be
answered by a string catalog the app ships (.xcstrings or a flat JSON map).
Nothing is modified; the JSON result goes to stdout.
"""
import argparse
import json
import os
import sys

from _shared import normalize_key, parse_langs


DOMAIN_DIRS = {
    "localization": ("Suggested", "LocalizationStrings"),
    "accessibility": ("AccessibilitySuggested", "AccessibilityStrings"),
}


def read_keys(opts):
    raw = [piece.strip() for piece in opts.keys.split(",")] if opts.keys else []
    if opts.keys_file:
        source = open(opts.keys_file, encoding="utf-8") if opts.keys_file != "-" else sys.stdin
        with source:
            raw += [line.strip() for line in source]
    return list(dict.fromkeys(key for key in raw if key))


def suggested_dir(opts):
    if opts.suggested_dir:
        return opts.suggested_dir
    snapshot_name, source_name = DOMAIN_DIRS[opts.domain]
    root = opts.resources_root
    snapshot = os.path.join(root, "Localization", snapshot_name)
    if os.path.isdir(snapshot):
        return snapshot
    return os.path.join(root, "Resources", "Localization", source_name, "Sources", "Suggested")


def read_json(path):
    with open(path, encoding="utf-8") as stream:
        return json.load(stream)


def xcstrings_values(entry):
    found = {}
    for lang, localization in ((entry or {}).get("localizations") or {}).items():
        unit = (localization or {}).get("stringUnit") or {}
        if "value" in unit:
            found[lang] = unit["value"]
    return found


def load_catalog(path):
    data = read_json(path)
    if not isinstance(data, dict):
        return {}
    strings = data.get("strings")
    if isinstance(strings, dict):
        return {key: xcstrings_values(entry) for key, entry in strings.items()}
    return data


def read_suggested(path, langs):
    data = read_json(path)
    per_lang = data if isinstance(data, dict) else {}

    def value_of(lang):
        block = per_lang.get(lang)
        return block.get("value") if isinstance(block, dict) else None

    return {lang: value_of(lang) for lang in langs}


def present_langs(directory, catalog, keys):
    found = []
    for key in keys:
        path = os.path.join(directory, normalize_key(key) + ".json")
        if os.path.isfile(path):
            data = read_json(path)
            found.extend(data.keys() if isinstance(data, dict) else [])
        for candidate in dict.fromkeys((key, normalize_key(key))):
            entry = (catalog or {}).get(candidate)
            if isinstance(entry, dict):
                found.extend(entry.keys())
    return found


def from_catalog(catalog, key, langs):
    for candidate in dict.fromkeys((key, normalize_key(key))):
        entry = catalog.get(candidate)
        if not isinstance(entry, dict):
            continue
        values = {lang: entry.get(lang) for lang in langs}
        if any(value is not None for value in values.values()):
            return values
    return None


def main():
    cli = argparse.ArgumentParser(description=__doc__.splitlines()[0])
    cli.add_argument("--keys", help="keys separated by commas, in code form or file form")
    cli.add_argument("--keys-file", help="one key per line; use - to read stdin")
    cli.add_argument("--resources-root", help="root of the resources checkout or of its snapshot")
    cli.add_argument("--suggested-dir", help="use this Suggested folder instead of looking for one")
    cli.add_argument("--domain", default="localization", choices=sorted(DOMAIN_DIRS))
    cli.add_argument("--catalog", help="string catalog the app ships (.xcstrings or flat JSON), consulted when a key has no Suggested file")
    cli.add_argument("--report-source", action="store_true", help="return {source, values} per key instead of the bare values")
    cli.add_argument("--langs", default="all", help="languages separated by commas, or 'all' for every language the sources hold")
    opts = cli.parse_args()

    keys = read_keys(opts)
    if not keys:
        cli.error("supply --keys and/or --keys-file")
    if not (opts.resources_root or opts.suggested_dir):
        cli.error("supply --resources-root or --suggested-dir")
    directory = suggested_dir(opts)
    if not os.path.isdir(directory):
        cli.error(f"no Suggested folder at {directory} (check --resources-root / --suggested-dir / --domain)")

    catalog = load_catalog(opts.catalog) if opts.catalog else None
    langs = parse_langs(opts.langs, present_langs(directory, catalog, keys) if opts.langs.strip() == "all" else ())

    result, via_catalog, unresolved = {}, [], []
    for key in keys:
        path = os.path.join(directory, normalize_key(key) + ".json")
        source, values = None, None
        if os.path.isfile(path):
            source, values = "suggested", read_suggested(path, langs)
        elif catalog is not None:
            values = from_catalog(catalog, key, langs)
            if values is not None:
                source = "catalog"
                via_catalog.append(key)
        if values is None:
            unresolved.append(key)
        result[key] = values if not opts.report_source else {"source": source, "values": values}

    json.dump(result, sys.stdout, indent=2, ensure_ascii=False)
    sys.stdout.write("\n")

    def listing(header, items):
        print(f"# {len(items)} key(s) {header}:", file=sys.stderr)
        for item in items:
            print(f"#   {item}", file=sys.stderr)

    if via_catalog:
        listing("came from the catalog because the snapshot lacks them; run snapshot-resources.sh to refresh it", via_catalog)
    if unresolved:
        if catalog is None:
            listing("are not in the snapshot (without --catalog, calling them 'unauthored' is UNVERIFIED)", unresolved)
        else:
            listing("have no authored source anywhere", unresolved)


if __name__ == "__main__":
    main()
