﻿"""
Incorpora lo cosechado por el WD14 a los wildcards de la progresion.

Solo las POSES: el harvest da 42 tags contra los 10 de los wildcards NSFW, y la
repeticion era el problema. Las ESCENAS no se tocan: sus lineas son
composiciones con luz ('bedroom, candlelight, romantic') mientras que las del
harvest son tags sueltos genericos ('indoors', 'outdoors') mas algun basura.

OJO: este merge se aplico con el harvest ANTERIOR (53% conservado, sin bucket
camera). El harvest actual es mas limpio, asi que las pools de la progresion
tienen 5 poses y 14 estados que el harvest ya no produce. Re-ejecuta con
--dry-run y revisa el diff antes de --apply.

    python Engine/merge_harvest_wildcards.py            # dry-run
    python Engine/merge_harvest_wildcards.py --apply
"""
import argparse
import re
import shutil
from datetime import datetime
from pathlib import Path

BASE = Path(__file__).resolve().parent.parent
PROG = BASE / "Archivos" / "progression_wildcards"
HARV = BASE / "Archivos" / "wildcards_harvest"
BACKUP = BASE / "_legacy" / "Datos" / "progression_wildcards_antes_harvest"

# Del harvest solo interesan las posturales/acciones. Se descartan las de
# mirada (looking_at_*) y de encuadre (from_behind) porque se repiten en todas
# las escenas y no aportan variedad, ademas de otras debiles.
POSE_KEEP = {
    "lying", "on_back", "on_stomach", "on_side", "all_fours", "prone_bone",
    "straddling", "girl_on_top", "spread_legs", "spread_ass", "cowgirl_position",
    "reverse_cowgirl_position", "squatting_cowgirl_position", "sex_from_behind",
    "standing_sex", "fellatio", "bent_over", "leaning_forward", "facing_away",
    "hands_on_own_ass", "grabbing_own_ass", "grabbing_another's_ass",
    "squatting", "kneeling", "sitting", "standing", "arms_up", "leaning_back",
}
POSE_DROP_REASON = {
    "looking_at_viewer": "mirada", "looking_back": "mirada",
    "looking_at_another": "mirada", "from_behind": "encuadre",
    "on_bed": "escena, ya esta en scenes.txt", "leg_lift": "debil",
    "bra_pull": "ropa, no postura", "grabbing_own_breast": "ropa, no postura",
    "legs_up": "debil", "feet_up": "debil", "arm_up": "debil",
    "standing_on_one_leg": "ya hay una equivalente",
}

# Estados NSFW: no existia ningun pool, el harvest aporta ~30 nuevos.
STATE_KEEP_RE = re.compile(
    r"^(penis|nipples|uncensored|sex|pussy|vaginal|nude|completely_nude|cum.*|"
    r"clothed_sex|breasts_out|ass_grab|erection|breasts_squeezed_together|"
    r"ass_focus|ejaculation|after_sex|covered_nipples|underboob|pussy_peek|"
    r"clothed_male_nude_female|sideboob|internal_cumshot|after_vaginal|"
    r"pussy_juice|veiny_penis|mixed-sex_bathing|same-sex_bathing)$"
)


def read(p):
    return [l.strip() for l in p.read_text(encoding="utf-8-sig").splitlines()
            if l.strip() and not l.strip().startswith("#")]


def write(p, lines):
    p.write_text("\n".join(lines) + "\n", encoding="utf-8", newline="\n")


# Cada paso tiene su nivel. Meter 'fellatio' en el paso 4 (presenting)
# romperia la escalada 1..7 que diseñaste, asi que el pool se reparte.
STEP_POSES = {
    "step4_presenting.txt": {
        "lying", "on_back", "on_stomach", "on_side", "all_fours", "prone_bone",
        "straddling", "spread_legs", "spread_ass", "girl_on_top", "arms_up",
        "facing_away", "bent_over", "grabbing_own_ass", "hands_on_own_ass",
        "leaning_back", "sitting",
    },
    "step5_sexual.txt": {
        "lying", "on_back", "on_stomach", "on_side", "all_fours", "prone_bone",
        "straddling", "spread_legs", "spread_ass", "girl_on_top", "arms_up",
        "facing_away", "bent_over", "grabbing_own_ass", "hands_on_own_ass",
        "leaning_back", "sitting", "fellatio", "grabbing_another's_ass",
        "squatting_cowgirl_position", "reverse_cowgirl_position", "leaning_forward",
        "squatting", "kneeling", "standing",
    },
    "step6_explicit.txt": POSE_KEEP,
    "step7_climax.txt": POSE_KEEP,
}


def main():
    ap = argparse.ArgumentParser()
    ap.add_argument("--apply", action="store_true")
    args = ap.parse_args()

    harvest_poses = read(HARV / "pose.txt")
    keep = [t for t in harvest_poses if t in POSE_KEEP]
    dropped = [t for t in harvest_poses if t not in POSE_KEEP]
    states = [t for t in read(HARV / "state.txt") if STATE_KEEP_RE.match(t)]

    print(f"harvest: {len(harvest_poses)} poses -> {len(keep)} utilizables, "
          f"{len(dropped)} descartadas")
    for t in dropped:
        print(f"   -{t:26} {POSE_DROP_REASON.get(t, 'no es postura')}")
    print(f"\nstates NSFW nuevos: {len(states)}")

    targets = list(STEP_POSES)
    plan = {}
    for name in targets:
        p = PROG / name
        if not p.exists():
            continue
        cur = read(p)
        new = list(cur)
        allowed = STEP_POSES[name]
        added = []
        for t in keep:
            if t not in allowed:
                continue
            if not any(t in line for line in new):
                new.append(t)
                added.append(t)
        plan[name] = (cur, new, added)

    print("\nplan por fichero:")
    total_added = 0
    for name, (cur, new, added) in plan.items():
        total_added += len(added)
        print(f"  {name:26} {len(cur):3} -> {len(new):3}  (+{len(added)})")
        if added:
            print(f"      {', '.join(added)}")

    state_new = states
    print(f"\n  {'step_state.txt':26}   0 -> {len(state_new):3}  (fichero nuevo, "
          f"para los pasos 5-7)")
    print(f"\ntotal de lineas anadidas: {total_added + len(state_new)}")

    if not args.apply:
        print("\n[DRY-RUN] nada escrito. Usa --apply.")
        return

    if BACKUP.exists():
        raise SystemExit(f"[!] El backup ya existe, no lo sobrescribo: {BACKUP}")
    shutil.copytree(PROG, BACKUP)

    for name, (cur, new, added) in plan.items():
        write(PROG / name, new)
    write(PROG / "step_state.txt", state_new)

    print(f"\n[OK] backup  -> {BACKUP}")
    print(f"[OK] pools NSFW ampliados: {len(plan)} ficheros + step_state.txt nuevo")


if __name__ == "__main__":
    main()