#!/usr/bin/env nu
# sync-page-ftl.nu
# Extracts data-key/data-en/data-es from a source index.html and writes FTL files.
#
# Usage:
#   nu scripts/sync/sync-page-ftl.nu --html <path> --out-en <path> --out-es <path>
#   nu scripts/sync/sync-page-ftl.nu --html <path> --out-en <path> --out-es <path> --dry-run
#
# Convention required in source HTML:
#   <element data-key="ftl-key-name" data-en="English text" data-es="Texto español">

def main [
    --html: string,         # Absolute path to source index.html
    --out-en: string,       # Output path for English FTL
    --out-es: string,       # Output path for Spanish FTL
    --dry-run               # Print changes without writing
] {
    if not ($html | path exists) {
        error make { msg: $"Source HTML not found: ($html)" }
    }

    let content = open $html

    # Normalize multiline tags: collapse newlines + surrounding whitespace to a single space.
    # This handles HTML where data-key, data-en, data-es are on separate lines within a tag.
    let flat = $content | str replace --all --regex '\n[ \t]+' ' '

    # Strategy: regex with a separator that skips quoted attribute values containing > or <.
    # Covers all 6 orderings of data-key / data-en / data-es within a tag.
    #
    # q = (?:"[^"]*"|[^>"])*?  — matches space between attrs, skipping complete "..." values
    # Built via concatenation to avoid Nu interpolation parsing ( as expression.
    let k = 'data-key="(?P<key>[^"]+)"'
    let e = 'data-en="(?P<en>[^"]*)"'
    let s = 'data-es="(?P<es>[^"]*)"'
    let q = '(?:"[^"]*"|[^>"])*?'
    let pat_kes = ($k + $q + $e + $q + $s)
    let pat_kse = ($k + $q + $s + $q + $e)
    let pat_eks = ($e + $q + $k + $q + $s)
    let pat_esk = ($e + $q + $s + $q + $k)
    let pat_ske = ($s + $q + $k + $q + $e)
    let pat_sek = ($s + $q + $e + $q + $k)

    let all_entries = (
        [
            ($flat | parse --regex $pat_kes),
            ($flat | parse --regex $pat_kse),
            ($flat | parse --regex $pat_eks),
            ($flat | parse --regex $pat_esk),
            ($flat | parse --regex $pat_ske),
            ($flat | parse --regex $pat_sek),
        ]
        | flatten
        | uniq-by key
        | sort-by key
    )

    if ($all_entries | length) == 0 {
        print $"⚠ No data-key elements found in ($html)"
        print "  Ensure elements have: data-key=\"ftl-key\" data-en=\"...\" data-es=\"...\""
        return
    }

    def decode-entities [val: string]: nothing -> string {
        $val
            | str replace --all "&amp;" "&"
            | str replace --all "&lt;" "<"
            | str replace --all "&gt;" ">"
            | str replace --all "&quot;" "\""
            | str replace --all "&#39;" "'"
            | str replace --all "&mdash;" "—"
            | str replace --all "&ndash;" "–"
            | str replace --all "&nbsp;" " "
            | str replace --all "&iacute;" "í"
            | str replace --all "&eacute;" "é"
            | str replace --all "&oacute;" "ó"
            | str replace --all "&uacute;" "ú"
            | str replace --all "&aacute;" "á"
            | str replace --all "&ntilde;" "ñ"
            | str replace --all "&#[0-9]+;" ""
    }

    # Parse existing FTL into a map of key→value (preserves manually-maintained keys)
    def parse-ftl [path: string]: nothing -> list<record<key: string, val: string>> {
        if not ($path | path exists) { return [] }
        open $path
            | lines
            | where { |l| not ($l | str starts-with '#') and ($l | str contains ' = ') }
            | each { |l|
                let idx = $l | str index-of ' = '
                let k = $l | str substring 0..<$idx
                let v = $l | str substring ($idx + 3)..
                { key: $k, val: $v }
            }
    }

    # Build HTML-extracted maps (key → decoded value)
    let html_en = $all_entries | each { |row| { key: $row.key, val: (decode-entities $row.en) } }
    let html_es = $all_entries | each { |row| { key: $row.key, val: (decode-entities $row.es) } }

    # Merge: start from existing FTL, update/add keys from HTML, preserve FTL-only keys
    def merge-ftl [existing: list<record<key: string, val: string>>, from_html: list<record<key: string, val: string>>]: nothing -> string {
        let html_map = $from_html | reduce -f {} { |row, acc| $acc | insert $row.key $row.val }
        let merged = $existing | each { |row|
            let updated = $html_map | get -o $row.key
            if $updated != null { { key: $row.key, val: $updated } } else { $row }
        }
        # Add new keys from HTML that weren't in existing FTL
        let existing_keys = $existing | get key
        let new_keys = $from_html | where { |row| not ($existing_keys | any { |k| $k == $row.key }) }
        ($merged | append $new_keys) | each { |row| $"($row.key) = ($row.val)" } | str join "\n"
    }

    let existing_en = parse-ftl $out_en
    let existing_es = parse-ftl $out_es

    let ftl_en = if ($existing_en | length) > 0 {
        merge-ftl $existing_en $html_en
    } else {
        $html_en | each { |row| $"($row.key) = ($row.val)" } | str join "\n"
    }

    let ftl_es = if ($existing_es | length) > 0 {
        merge-ftl $existing_es $html_es
    } else {
        $html_es | each { |row| $"($row.key) = ($row.val)" } | str join "\n"
    }

    print $"  Found ($all_entries | length) translatable keys from HTML"

    if $dry_run {
        print "\n── EN (preview first 10) ──"
        print ($ftl_en | lines | first 10 | str join "\n")
        print "\n── ES (preview first 10) ──"
        print ($ftl_es | lines | first 10 | str join "\n")
        return
    }

    # Write EN
    let current_en = if ($out_en | path exists) { open $out_en } else { "" }
    if $ftl_en != $current_en {
        $ftl_en | save --force $out_en
        print $"  ✓ ($out_en)"
    } else {
        print $"  — ($out_en) unchanged"
    }

    # Write ES
    let current_es = if ($out_es | path exists) { open $out_es } else { "" }
    if $ftl_es != $current_es {
        $ftl_es | save --force $out_es
        print $"  ✓ ($out_es)"
    } else {
        print $"  — ($out_es) unchanged"
    }
}
