<?php
/**
 * Helper PHP para translate_post.py — corre DENTRO del contenedor WP cargando wp-load.php
 * (no necesita wp-cli ni proc_open). Centraliza la lógica de WordPress/Polylang.
 *
 * Uso (vía `docker exec wordpress-web php /tmp/fea_translate_helper.php <subcomando> ...`):
 *   read   <id>                  → JSON {id,title,content,excerpt,lang,status,author,date,cats}
 *   read_full <id>               → JSON con slug, metas, categorías y grupo Polylang
 *   exists <es_id> <lang>        → imprime el ID de la traducción en <lang> (0 si no hay)
 *   create <es_id> <lang> <status>  (lee {title,content} por stdin)
 *                                → crea el post traducido, lo enlaza con Polylang y mete metas;
 *                                  imprime el nuevo ID.
 *   clone <target_id> <lang> <status> (lee payload JSON por stdin)
 *                                → inserta/actualiza un post con ID explícito, categorías y metas.
 *   save_translations            → guarda un grupo Polylang exacto leído por stdin.
 *
 * Ver issue rafa/feadulta#75.
 */

// Bootstrap portable. Si WP no está cargado (modo standalone), cargar wp-load.
//   Local (docker): /var/www/html/wp-load.php (por defecto).
//   Prod:           export FEA_WP_LOAD=/web/wp-load.php
// (Si se ejecuta vía `wp eval-file`, ABSPATH ya está definido y no se recarga.)
if (!defined('ABSPATH')) {
    $_SERVER['REQUEST_URI'] = $_SERVER['REQUEST_URI'] ?? '/';
    $_SERVER['HTTP_HOST']   = $_SERVER['HTTP_HOST'] ?? 'localhost';
    require_once (getenv('FEA_WP_LOAD') ?: '/var/www/html/wp-load.php');
}

if (!function_exists('pll_set_post_language')) {
    fwrite(STDERR, "Polylang no disponible\n");
    exit(2);
}

$cmd = $argv[1] ?? '';

function out_json($data): void { echo wp_json_encode($data); }

function meta_payload(int $id): array {
    $raw = get_post_meta($id);
    $out = [];
    foreach ($raw as $key => $values) {
        if (in_array($key, ['_edit_lock', '_edit_last'], true)) {
            continue;
        }
        $out[$key] = array_map('maybe_unserialize', (array) $values);
    }
    return $out;
}

function normalize_meta_input(array $payload): array {
    $meta = $payload['meta'] ?? [];
    if (!is_array($meta)) {
        return [];
    }
    $out = [];
    foreach ($meta as $key => $values) {
        if (!is_string($key) || $key === '') {
            continue;
        }
        if (!is_array($values)) {
            $values = [$values];
        }
        $out[$key] = $values;
    }
    return $out;
}

function set_meta_payload(int $id, array $meta): void {
    foreach ($meta as $key => $values) {
        delete_post_meta($id, $key);
        foreach ($values as $value) {
            add_post_meta($id, $key, maybe_serialize($value));
        }
    }
}

switch ($cmd) {
    case 'read': {
        $id = (int) ($argv[2] ?? 0);
        $p  = get_post($id);
        if (!$p) { fwrite(STDERR, "post $id no existe\n"); exit(3); }
        out_json([
            'id'      => $p->ID,
            'title'   => $p->post_title,
            'content' => $p->post_content,
            'excerpt' => $p->post_excerpt,
            'lang'    => function_exists('pll_get_post_language') ? pll_get_post_language($id) : '',
            'status'  => $p->post_status,
            'author'  => (int) $p->post_author,
            'date'    => $p->post_date,
            'cats'    => wp_get_post_categories($id),
        ]);
        break;
    }

    case 'read_full': {
        $id = (int) ($argv[2] ?? 0);
        $p  = get_post($id);
        if (!$p) { fwrite(STDERR, "post $id no existe\n"); exit(3); }
        out_json([
            'id'           => $p->ID,
            'title'        => $p->post_title,
            'content'      => $p->post_content,
            'excerpt'      => $p->post_excerpt,
            'slug'         => $p->post_name,
            'lang'         => function_exists('pll_get_post_language') ? pll_get_post_language($id) : '',
            'status'       => $p->post_status,
            'author'       => (int) $p->post_author,
            'date'         => $p->post_date,
            'date_gmt'     => $p->post_date_gmt,
            'type'         => $p->post_type,
            'cats'         => wp_get_post_categories($id),
            'cat_slugs'    => array_values(array_map(static fn($t) => $t->slug, get_the_terms($id, 'category') ?: [])),
            'meta'         => meta_payload($id),
            'translations' => function_exists('pll_get_post_translations') ? pll_get_post_translations($id) : [],
        ]);
        break;
    }

    case 'exists': {
        $es   = (int) ($argv[2] ?? 0);
        $lang = (string) ($argv[3] ?? '');
        $t    = (int) pll_get_post($es, $lang);
        if ($t && !get_post($t)) $t = 0; // enlace colgado a un post borrado
        echo $t;
        break;
    }

    case 'unlink': {
        // Borra la traducción en <lang> y la saca del grupo (para --force / limpieza).
        $es   = (int) ($argv[2] ?? 0);
        $lang = (string) ($argv[3] ?? '');
        $t    = (int) pll_get_post($es, $lang);
        if ($t && get_post($t)) wp_delete_post($t, true);
        $tr = function_exists('pll_get_post_translations') ? pll_get_post_translations($es) : ['es' => $es];
        unset($tr[$lang]);
        if ($tr) pll_save_post_translations($tr);
        echo $t;
        break;
    }

    case 'create': {
        $es     = (int) ($argv[2] ?? 0);
        $lang   = (string) ($argv[3] ?? '');
        $status = (string) ($argv[4] ?? 'draft');
        $src    = get_post($es);
        if (!$src) { fwrite(STDERR, "post fuente $es no existe\n"); exit(3); }

        $payload = json_decode(file_get_contents('php://stdin'), true);
        if (!is_array($payload) || empty($payload['title'])) {
            fwrite(STDERR, "payload inválido por stdin\n"); exit(4);
        }

        // ¿ya existe (y vivo)? idempotencia dura.
        $existing = (int) pll_get_post($es, $lang);
        if ($existing && !get_post($existing)) $existing = 0;
        if ($existing) { echo $existing; break; }

        $new_id = wp_insert_post([
            'post_title'   => wp_slash($payload['title']),
            'post_content' => wp_slash($payload['content'] ?? ''),
            'post_excerpt' => wp_slash($payload['excerpt'] ?? ''),
            'post_name'    => sanitize_title($payload['title']),
            'post_status'  => $status,
            'post_type'    => 'post',
            'post_author'  => (int) $src->post_author,
            'post_date'    => $src->post_date,
            'to_ping'      => '',
            'pinged'       => '',
        ], true);

        if (is_wp_error($new_id)) { fwrite(STDERR, $new_id->get_error_message() . "\n"); exit(5); }

        // Idioma primero, para que las categorías traducidas casen con el idioma del post.
        pll_set_post_language($new_id, $lang);

        // Categorías: mapea cada categoría ES a su traducción en el idioma destino
        // (las categorías de carta ya están traducidas: cartasemana 6→en 3077, fr 3083…).
        $cats   = wp_get_post_categories($es);
        $mapped = [];
        foreach ($cats as $c) {
            $tc = function_exists('pll_get_term') ? (int) pll_get_term($c, $lang) : 0;
            $mapped[] = $tc ?: $c; // traducida si existe; si no, la ES (fallback)
        }
        if ($mapped) wp_set_post_categories($new_id, array_values(array_unique($mapped)));

        // Enlace de traducción (preservando el grupo existente).
        $tr = function_exists('pll_get_post_translations') ? pll_get_post_translations($es) : ['es' => $es];
        if (!$tr) $tr = ['es' => $es];
        $tr[$lang] = $new_id;
        pll_save_post_translations($tr);

        // Metas de trazabilidad.
        update_post_meta($new_id, 'traduccion_automatica', '1');
        update_post_meta($new_id, 'traduccion_origen', $es);
        update_post_meta($new_id, 'traduccion_modelo', $payload['model'] ?? '');
        update_post_meta($new_id, 'traduccion_fecha', gmdate('c'));

        echo $new_id;
        break;
    }

    case 'clone': {
        $target = (int) ($argv[2] ?? 0);
        $lang   = (string) ($argv[3] ?? '');
        $status = (string) ($argv[4] ?? 'draft');
        if ($target <= 0 || $lang === '') {
            fwrite(STDERR, "uso: clone <target_id> <lang> <status>\n"); exit(6);
        }

        $payload = json_decode(file_get_contents('php://stdin'), true);
        if (!is_array($payload) || empty($payload['title'])) {
            fwrite(STDERR, "payload inválido por stdin\n"); exit(4);
        }

        $postarr = [
            'post_title'   => wp_slash($payload['title']),
            'post_content' => wp_slash($payload['content'] ?? ''),
            'post_excerpt' => wp_slash($payload['excerpt'] ?? ''),
            'post_status'  => $status ?: ($payload['status'] ?? 'draft'),
            'post_type'    => $payload['type'] ?? 'post',
            'post_author'  => (int) ($payload['author'] ?? 1),
            'post_date'    => $payload['date'] ?? current_time('mysql'),
            'post_date_gmt'=> $payload['date_gmt'] ?? current_time('mysql', true),
            'post_name'    => $payload['slug'] ?? '',
            'to_ping'      => '',
            'pinged'       => '',
        ];

        $existing = get_post($target);
        if ($existing) {
            $postarr['ID'] = $target;
            $new_id = wp_update_post($postarr, true);
        } else {
            $postarr['import_id'] = $target;
            $new_id = wp_insert_post($postarr, true);
        }

        if (is_wp_error($new_id)) { fwrite(STDERR, $new_id->get_error_message() . "\n"); exit(5); }
        if ((int) $new_id !== $target) {
            fwrite(STDERR, "ID preservado falló: esperado $target, creado $new_id\n"); exit(7);
        }

        pll_set_post_language($new_id, $lang);

        $cats = [];
        foreach ((array) ($payload['cat_slugs'] ?? []) as $slug) {
            $term = get_term_by('slug', (string) $slug, 'category');
            if ($term && !is_wp_error($term)) {
                $cats[] = (int) $term->term_id;
            }
        }
        if (!$cats) {
            $cats = array_values(array_unique(array_map('intval', (array) ($payload['cats'] ?? []))));
        }
        wp_set_post_categories($new_id, $cats);

        set_meta_payload($new_id, normalize_meta_input($payload));
        clean_post_cache($new_id);
        echo $new_id;
        break;
    }

    case 'carta_sections': {
        // Descubre el cluster de una carta parseando sus propios enlaces internos
        // (misma lógica que pinta la portada, fea-carta-portada.php). No depende
        // de _carta_id -> sirve aunque ese meta todavía no se haya puesto.
        $id = (int) ($argv[2] ?? 0);
        if (!$id || !function_exists('fea_parse_carta_sections')) {
            fwrite(STDERR, "fea_parse_carta_sections no disponible o id inválido\n"); exit(9);
        }
        out_json(fea_parse_carta_sections($id));
        break;
    }

    case 'save_translations': {
        $payload = json_decode(file_get_contents('php://stdin'), true);
        if (!is_array($payload) || empty($payload['translations']) || !is_array($payload['translations'])) {
            fwrite(STDERR, "payload inválido por stdin\n"); exit(4);
        }
        $tr = [];
        foreach ($payload['translations'] as $lang => $id) {
            $id = (int) $id;
            if (!is_string($lang) || $lang === '' || $id <= 0 || !get_post($id)) {
                continue;
            }
            $tr[$lang] = $id;
        }
        if (count($tr) < 2) {
            fwrite(STDERR, "grupo insuficiente\n"); exit(8);
        }
        pll_save_post_translations($tr);
        out_json($tr);
        break;
    }

    default:
        fwrite(STDERR, "subcomando desconocido: '$cmd'\n");
        exit(1);
}
