#!/usr/bin/env python3
"""
apply_translations.py — Overlay Hungarian text on High Orbit card PNGs.

Usage:
    python apply_translations.py              # process all cards
    python apply_translations.py --test       # test mode: one card per type -> output/test/
    python apply_translations.py --card "Orbital Headquarters"  # single card type

Card layout (822 x 1122 px @ 300 DPI):
  - Title band:       y=188–226, full width inside border
  - Restriction:      y=242–265 (Orbital HQ only)
  - Effect text:      y=342–478, below the icon row
  - Flavor strip:     y=904–1022 (light background); text from ~y=930
  - VP cards: flavor text x=92–618 (narrower — VP icon sits on right at x≈638+)
  - Non-VP cards:     x=92–730
"""

import os
import sys
import glob
import json
import textwrap
import argparse
import importlib.util as _ilu
import numpy as np
from PIL import Image, ImageDraw, ImageFont

# ---------------------------------------------------------------------------
# Import gradient_fill for background reconstruction
# ---------------------------------------------------------------------------
_scripts_dir = os.path.dirname(os.path.abspath(__file__))
_gf_spec = _ilu.spec_from_file_location(
    "gradient_fill", os.path.join(_scripts_dir, "gradient_fill.py")
)
_gf_mod = _ilu.module_from_spec(_gf_spec)
_gf_spec.loader.exec_module(_gf_mod)
background_row_fill = _gf_mod.background_row_fill

# ---------------------------------------------------------------------------
# Paths
# ---------------------------------------------------------------------------
BASE_DIR          = r"C:\progik\forditsunk"
SOURCE_DIR        = os.path.join(BASE_DIR, r"source\High_Orbit\High Orbit")
OUTPUT_DIR        = os.path.join(BASE_DIR, "output", "cards")
FONTS_DIR         = r"C:\Windows\Fonts"
TRANSLATIONS_FILE = os.path.join(BASE_DIR, 'translations', 'cards.json')

FONT_TITLE  = os.path.join(FONTS_DIR, "arialbd.ttf")    # Arial Bold — title
FONT_BODY   = os.path.join(FONTS_DIR, "calibri.ttf")    # Calibri — effect text
FONT_FLAVOR = os.path.join(FONTS_DIR, "georgiaz.ttf")   # Georgia Bold Italic — flavor

# ---------------------------------------------------------------------------
# Card geometry (pixels, 822 x 1122)
# ---------------------------------------------------------------------------
W, H = 822, 1122

REGION_TITLE        = (92,  188, 730, 227)    # title band
REGION_RESTRICT     = (92,  242, 480, 267)    # restriction (Orbital HQ only)
REGION_EFFECT       = (92,  342, 730, 478)    # effect/action text body
REGION_FLAVOR_STD   = (92,  904, 730, 1022)   # standard cards (no VP icon)
REGION_FLAVOR_VP    = (92,  904, 618, 1022)   # VP cards — narrower; VP icon at x≈638+

BG_TITLE   = (148, 148, 148)
BG_EFFECT  = (200, 200, 200)
BG_FLAVOR  = (196, 196, 196)

COLOR_DARK = (28, 28, 28)
COLOR_TITLE_TEXT = (30, 30, 30)

SIZE_TITLE    = 28   # px
SIZE_RESTRICT = 19
SIZE_BODY     = 19
SIZE_FLAVOR   = 19

# ---------------------------------------------------------------------------
# Translation data — loaded from translations/cards.json
# ---------------------------------------------------------------------------

TRANSLATIONS = json.load(open(TRANSLATIONS_FILE, encoding='utf-8'))

# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------

def load_font(path, size):
    try:
        return ImageFont.truetype(path, size)
    except Exception as e:
        print(f"  Warning: could not load {path}: {e}. Using default font.")
        return ImageFont.load_default()


def wrap_to_lines(text, font, max_px, draw):
    """Word-wrap text to fit within max_px wide. Returns list of strings."""
    words = text.split()
    lines = []
    current = []
    for word in words:
        test = " ".join(current + [word])
        bb = draw.textbbox((0, 0), test, font=font)
        if bb[2] <= max_px:
            current.append(word)
        else:
            if current:
                lines.append(" ".join(current))
            current = [word]
    if current:
        lines.append(" ".join(current))
    return lines


def draw_region(img, region, paragraphs, font, bg_color, text_color,
                halign="center", valign="center", pad_x=10, pad_y=6, line_gap=3):
    """Fill region using gradient_fill.background_row_fill, then render paragraphs of wrapped text.

    background_row_fill reconstructs the card's original gradient background by
    removing existing dark text pixels via per-row median sampling — giving a
    seamless, artifact-free fill that matches the card's actual gradient instead
    of a hardcoded solid color.  Falls back to solid bg_color if numpy is
    unavailable.
    """
    x1, y1, x2, y2 = region
    # --- Gradient fill: reconstruct background from card pixels -------------
    try:
        # Convert PIL image to RGB numpy array, inpaint the region, paste back
        arr = np.array(img.convert("RGB"))
        arr = background_row_fill(arr, x1, y1, x2, y2)
        # Paste the cleaned region back into img (preserving alpha if present)
        clean_patch = Image.fromarray(arr[y1:y2, x1:x2], "RGB")
        img.paste(clean_patch, (x1, y1))
    except Exception:
        # Fallback: solid fill (original behavior)
        draw_fb = ImageDraw.Draw(img)
        draw_fb.rectangle([x1, y1, x2, y2], fill=bg_color)
    # -------------------------------------------------------------------------
    draw = ImageDraw.Draw(img)

    max_w = x2 - x1 - 2 * pad_x
    sample_bb = draw.textbbox((0, 0), "Ag", font=font)
    line_h = (sample_bb[3] - sample_bb[1]) + line_gap

    # Flatten paragraphs into lines with an extra gap between paragraphs
    all_lines = []
    for i, para in enumerate(paragraphs):
        wrapped = wrap_to_lines(para, font, max_w, draw)
        all_lines.extend(wrapped)
        if i < len(paragraphs) - 1:
            all_lines.append("")   # blank separator

    total_h = len(all_lines) * line_h
    region_h = y2 - y1 - 2 * pad_y

    if valign == "center":
        y = y1 + pad_y + max(0, (region_h - total_h) // 2)
    else:
        y = y1 + pad_y

    for line in all_lines:
        if not line:
            y += line_h
            continue
        bb = draw.textbbox((0, 0), line, font=font)
        tw = bb[2] - bb[0]
        if halign == "center":
            x = x1 + (x2 - x1 - tw) // 2
        else:
            x = x1 + pad_x
        draw.text((x, y), line, font=font, fill=text_color)
        y += line_h


def find_source_files(card_name, glob_pattern):
    """Return sorted list of matching PNGs across all card subfolders."""
    folders = [
        os.path.join(SOURCE_DIR, "High_Orbit_Professional_Print_Cards_1"),
        os.path.join(SOURCE_DIR, "High_Orbit_Professional_Print_Cards_2"),
        os.path.join(SOURCE_DIR, "High_Orbit_Professional_Print_Cards_3_1"),  # prefer updated
        os.path.join(SOURCE_DIR, "High_Orbit_Professional_Print_Cards_3"),
    ]
    seen = set()
    results = []
    for folder in folders:
        pattern = os.path.join(folder, f"*{card_name}*.png")
        for path in sorted(glob.glob(pattern)):
            fname = os.path.basename(path)
            # deduplicate: _3_1 takes precedence over _3 for same basename
            if fname not in seen:
                seen.add(fname)
                results.append(path)
    return results


# ---------------------------------------------------------------------------
# Main processing
# ---------------------------------------------------------------------------

def process_card(card_name, data, out_dir, test_mode=False):
    files = find_source_files(card_name, data["source_glob"])
    if not files:
        print(f"  [WARN] No files found for: {card_name}")
        return 0

    if test_mode:
        files = files[:1]  # only first copy for test

    font_title  = load_font(FONT_TITLE,  SIZE_TITLE)
    font_body   = load_font(FONT_BODY,   SIZE_BODY)
    font_flavor = load_font(FONT_FLAVOR, SIZE_FLAVOR)
    font_small  = load_font(FONT_BODY,   SIZE_RESTRICT)

    count = 0
    for src_path in files:
        img = Image.open(src_path).convert("RGBA")

        # --- Title ---
        draw_region(
            img, REGION_TITLE,
            [data["title"].upper()],
            font_title, BG_TITLE, COLOR_TITLE_TEXT,
            halign="center", valign="center",
        )

        # --- Restriction (Orbital HQ only) ---
        if data.get("restriction"):
            draw_region(
                img, REGION_RESTRICT,
                [data["restriction"]],
                font_small, BG_EFFECT, COLOR_DARK,
                halign="left", valign="center",
            )

        # --- Pre-effect text (Auto Factory: action text sits between icon rows) ---
        if data.get("effect_pre"):
            draw_region(
                img, data["effect_pre_region"],
                data["effect_pre"],
                font_body, BG_EFFECT, COLOR_DARK,
                halign="center", valign="center",
            )

        # --- Effect text ---
        draw_region(
            img, REGION_EFFECT,
            data["effect"],
            font_body, BG_EFFECT, COLOR_DARK,
            halign="center", valign="center",
        )

        # --- Flavor text ---
        flavor_region = REGION_FLAVOR_VP if data.get("vp_card") else REGION_FLAVOR_STD
        draw_region(
            img, flavor_region,
            [data["flavor"]],
            font_flavor, BG_FLAVOR, COLOR_DARK,
            halign="center", valign="center",
        )

        # Save
        fname = os.path.basename(src_path)
        out_path = os.path.join(out_dir, fname)
        img.save(out_path, "PNG")
        count += 1

    return count


def main():
    parser = argparse.ArgumentParser(description="Overlay Hungarian text on High Orbit card PNGs")
    parser.add_argument("--test", action="store_true", help="Test mode: process one card per type")
    parser.add_argument("--card", type=str, default=None, help="Process only one card type by name")
    args = parser.parse_args()

    out_dir = os.path.join(OUTPUT_DIR, "test") if args.test else OUTPUT_DIR
    os.makedirs(out_dir, exist_ok=True)

    cards_to_process = TRANSLATIONS
    if args.card:
        key = args.card
        if key not in TRANSLATIONS:
            # case-insensitive search
            matches = [k for k in TRANSLATIONS if k.lower() == key.lower()]
            if matches:
                key = matches[0]
            else:
                print(f"Card '{args.card}' not found. Available: {list(TRANSLATIONS.keys())}")
                sys.exit(1)
        cards_to_process = {key: TRANSLATIONS[key]}

    total = 0
    for card_name, data in cards_to_process.items():
        print(f"Processing: {card_name}...")
        n = process_card(card_name, data, out_dir, test_mode=args.test)
        print(f"  -> {n} file(s) saved")
        total += n

    print(f"\nDone. {total} card(s) saved to: {out_dir}")


if __name__ == "__main__":
    main()
