<?php
session_start();
include '../includes/session_control.php';
require_once __DIR__ . '/../cotizaciones/api/_node.php';

$token = cpn_node_token_or_fail();
$nodeBase = cpn_node_api_base();

// Proxy AJAX (misma página, para no crear archivos extra)
if (isset($_GET['ajax'])) {
    header('Content-Type: application/json; charset=utf-8');

    $action = $_GET['action'] ?? '';
    $method = $_SERVER['REQUEST_METHOD'] ?? 'GET';

    $jsonBody = [];
    if ($method === 'POST') {
        $raw = file_get_contents('php://input');
        $decoded = json_decode($raw, true);
        if (is_array($decoded)) $jsonBody = $decoded;
    }

    try {
        $nodeGet = function ($path, $query = []) use ($nodeBase, $token) {
            $url = $nodeBase . $path;
            if (!empty($query)) {
                $qs = http_build_query($query);
                $url .= (strpos($url, '?') === false ? '?' : '&') . $qs;
            }
            return cpn_node_request('GET', $url, $token);
        };
        $nodePost = function ($path, $payload = []) use ($nodeBase, $token) {
            return cpn_node_request('POST', $nodeBase . $path, $token, $payload);
        };

        if ($method === 'GET' && $action === 'meta') {
            echo json_encode($nodeGet('/api/gastos/recurrentes/meta'));
            exit;
        }
        if ($method === 'GET' && $action === 'recurrentes') {
            echo json_encode($nodeGet('/api/gastos/recurrentes'));
            exit;
        }
        if ($method === 'POST' && $action === 'recurrenteCreate') {
            echo json_encode($nodePost('/api/gastos/recurrentes/create', $jsonBody));
            exit;
        }
        if ($method === 'POST' && $action === 'recurrenteUpdateField') {
            echo json_encode($nodePost('/api/gastos/recurrentes/update-field', $jsonBody));
            exit;
        }
        if ($method === 'POST' && $action === 'recurrenteDelete') {
            echo json_encode($nodePost('/api/gastos/recurrentes/delete', $jsonBody));
            exit;
        }
        if ($method === 'GET' && $action === 'instancias') {
            $recurrenteId = intval($_GET['recurrenteId'] ?? 0);
            $year = intval($_GET['year'] ?? intval(date('Y')));
            echo json_encode($nodeGet('/api/gastos/recurrentes/instancias', [
                'recurrenteId' => $recurrenteId,
                'year' => $year,
            ]));
            exit;
        }
        if ($method === 'POST' && $action === 'instanciaUpdateField') {
            echo json_encode($nodePost('/api/gastos/recurrentes/instancias/update-field', $jsonBody));
            exit;
        }
        if ($method === 'POST' && $action === 'generarGasto') {
            echo json_encode($nodePost('/api/gastos/recurrentes/instancias/generar-gasto', $jsonBody));
            exit;
        }

        // Proxies para Select2 (Node requiere Authorization)
        if ($method === 'GET' && $action === 'searchTerceros') {
            $q = $_GET['q'] ?? $_GET['term'] ?? '';
            echo json_encode($nodeGet('/api/gastos/terceros/search', ['q' => $q]));
            exit;
        }
        if ($method === 'GET' && $action === 'searchConceptos') {
            $q = $_GET['q'] ?? $_GET['term'] ?? '';
            echo json_encode($nodeGet('/api/gastos/conceptos/search', ['q' => $q]));
            exit;
        }
        if ($method === 'GET' && $action === 'searchCuentas') {
            $q = $_GET['q'] ?? $_GET['term'] ?? '';
            echo json_encode($nodeGet('/api/gastos/cuentas/search', ['q' => $q]));
            exit;
        }

        echo json_encode(['ok' => false, 'error' => ['message' => 'Acción no soportada']]);
        exit;
    } catch (Throwable $e) {
        echo json_encode(['ok' => false, 'error' => ['message' => $e->getMessage()]]);
        exit;
    }
}

require_once __DIR__ . '/../templates/header.php';
?>

<style>
    .table td,
    .table th {
        vertical-align: middle;
    }

    .table-sm td,
    .table-sm th {
        padding: .35rem;
    }

    .cpn-muted {
        opacity: .85;
    }

    .cpn-small {
        font-size: 12px;
    }

    .cpn-actions .btn {
        padding: .25rem .45rem;
    }

    /* Select2 dark (solo select2) */
    .select2-container--default .select2-selection--single {
        background-color: #2c2f33;
        border: 1px solid #4b5563;
        height: 34px;
    }

    .select2-container--default .select2-selection--single .select2-selection__rendered {
        color: #e5e7eb;
        line-height: 32px;
    }

    .select2-container--default .select2-selection--single .select2-selection__arrow {
        height: 32px;
    }

    .select2-dropdown {
        background-color: #1f2937;
        border: 1px solid #4b5563;
    }

    .select2-results__option {
        color: #e5e7eb;
    }

    .select2-container--default .select2-results__option--highlighted[aria-selected] {
        background-color: #374151;
        color: #ffffff;
    }

    .select2-container--default .select2-results__option[aria-selected=true] {
        background-color: #111827;
        color: #ffffff;
    }

    /* Asegura dropdown arriba del modal */
    .select2-container--open,
    .select2-dropdown {
        z-index: 1060;
    }
</style>

<div class="container-fluid">
    <div class="d-sm-flex align-items-center justify-content-between mb-3">
        <h1 class="h4 mb-0 text-gray-200">Gastos Recurrentes</h1>
        <div>
            <button class="btn btn-sm btn-primary" id="btnNewRecurrente"><i class="fas fa-plus"></i> Nueva recurrencia</button>
        </div>
    </div>

    <div class="card shadow mb-3">
        <div class="card-header py-2 d-flex align-items-center justify-content-between">
            <div class="font-weight-bold cpn-muted">Recurrencias</div>
            <div class="d-flex align-items-center">
                <div class="mr-2 cpn-small cpn-muted">Año instancias</div>
                <select id="selYear" class="form-control form-control-sm" style="width: 110px;"></select>
            </div>
        </div>
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-sm mb-0" id="tblRecurrentes">
                    <thead>
                        <tr>
                            <th style="width:70px;">ID</th>
                            <th>Empresa</th>
                            <th>Origen</th>
                            <th>Tercero</th>
                            <th>Concepto</th>
                            <th>Cuenta</th>
                            <th style="width:90px;" class="text-center">Día</th>
                            <th style="width:150px;">Inicio</th>
                            <th style="width:150px;">Fin</th>
                            <th style="width:130px;" class="text-right">Valor</th>
                            <th style="width:90px;" class="text-center">Activo</th>
                            <th style="width:160px;" class="text-center">Acciones</th>
                        </tr>
                    </thead>
                    <tbody></tbody>
                </table>
            </div>
        </div>
    </div>

    <div class="card shadow mb-3">
        <div class="card-header py-2 d-flex align-items-center justify-content-between">
            <div class="font-weight-bold cpn-muted">Instancias (por mes)</div>
            <div class="cpn-small cpn-muted" id="instanciasHint">Seleccione una recurrencia…</div>
        </div>
        <div class="card-body p-0">
            <div class="table-responsive">
                <table class="table table-sm mb-0" id="tblInstancias">
                    <thead>
                        <tr>
                            <th style="width:90px;">Periodo</th>
                            <th style="width:170px;">Vence</th>
                            <th style="width:170px;">Vence override</th>
                            <th style="width:140px;" class="text-right">Valor default</th>
                            <th style="width:140px;" class="text-right">Valor override</th>
                            <th style="width:130px;" class="text-center">Estado</th>
                            <th>Observación</th>
                            <th style="width:200px;" class="text-center">Acciones</th>
                        </tr>
                    </thead>
                    <tbody></tbody>
                </table>
            </div>
        </div>
    </div>
</div>

<!-- Modal crear/editar recurrencia -->
<div class="modal fade" id="modalRecurrente" tabindex="-1" role="dialog" aria-hidden="true" data-backdrop="static" data-keyboard="false">
    <div class="modal-dialog modal-lg" role="document">
        <div class="modal-content">
            <div class="modal-header py-2">
                <h5 class="modal-title">Nueva recurrencia</h5>
                <button type="button" class="close text-white" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
            </div>
            <div class="modal-body">
                <form id="frmRecurrente">
                    <div class="form-row">
                        <div class="form-group col-md-6">
                            <label class="cpn-small mb-1">Empresa</label>
                            <select id="mEmpresa" name="idEmpresa" class="form-control"></select>
                        </div>
                        <div class="form-group col-md-6">
                            <label class="cpn-small mb-1">Origen</label>
                            <select id="mOrigen" name="idOrigen" class="form-control"></select>
                        </div>
                    </div>

                    <div class="form-row">
                        <div class="form-group col-md-6">
                            <label class="cpn-small mb-1">Tercero</label>
                            <select id="mTercero" name="idTercero" class="form-control"></select>
                        </div>
                        <div class="form-group col-md-6">
                            <label class="cpn-small mb-1">Concepto</label>
                            <select id="mConcepto" name="idConcepto" class="form-control"></select>
                        </div>
                    </div>

                    <div class="form-row">
                        <div class="form-group col-md-6">
                            <label class="cpn-small mb-1">Cuenta</label>
                            <select id="mCuenta" name="idCuenta" class="form-control"></select>
                        </div>
                        <div class="form-group col-md-2">
                            <label class="cpn-small mb-1">Día del mes</label>
                            <input type="number" class="form-control" name="dayOfMonth" min="1" max="31" value="1" />
                        </div>
                        <div class="form-group col-md-4">
                            <label class="cpn-small mb-1">Valor default</label>
                            <input type="number" class="form-control" name="defaultAmount" step="1" min="0" value="0" />
                        </div>
                    </div>

                    <div class="form-row">
                        <div class="form-group col-md-4">
                            <label class="cpn-small mb-1">Fecha inicio</label>
                            <input type="date" class="form-control" name="startDate" />
                        </div>
                        <div class="form-group col-md-4">
                            <label class="cpn-small mb-1">Fecha fin</label>
                            <input type="date" class="form-control" name="endDate" />
                        </div>
                        <div class="form-group col-md-4">
                            <label class="cpn-small mb-1">Activo</label>
                            <select class="form-control" name="activo">
                                <option value="1" selected>Si</option>
                                <option value="0">No</option>
                            </select>
                        </div>
                    </div>
                </form>
                <div class="cpn-small cpn-muted">Tip: servicios públicos (valor variable) se manejan con override en instancias.</div>
            </div>
            <div class="modal-footer py-2">
                <button type="button" class="btn btn-sm btn-secondary" data-dismiss="modal">Cerrar</button>
                <button type="button" class="btn btn-sm btn-primary" id="btnSaveRecurrente">Guardar</button>
            </div>
        </div>
    </div>
</div>

<script>
    (function() {
        const API_BASE = window.location.pathname + '?ajax=1';

        let meta = null;
        let selectedRecurrenteId = null;
        let editingRecurrenteId = null;

        function pad2(n) {
            return (n < 10 ? '0' : '') + n;
        }

        // Formato: 25-Jun-25 8:30 pm (si viene con hora). Si viene solo date, muestra 25-Jun-25.
        function formatDateDisplay(value) {
            if (!value) return '';
            const s = String(value);
            // soporta "YYYY-MM-DD" o "YYYY-MM-DD HH:MM:SS"
            const parts = s.split(' ');
            const datePart = parts[0];
            const timePart = parts[1] || null;

            const dparts = datePart.split('-');
            if (dparts.length !== 3) return s;
            const y = parseInt(dparts[0], 10);
            const m = parseInt(dparts[1], 10);
            const d = parseInt(dparts[2], 10);

            const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
            const mon = months[Math.max(0, Math.min(11, m - 1))];
            const yy = String(y).slice(-2);

            if (!timePart) return pad2(d) + '-' + mon + '-' + yy;

            const tparts = timePart.split(':');
            let hh = parseInt(tparts[0] || '0', 10);
            const mm = parseInt(tparts[1] || '0', 10);
            const ampm = hh >= 12 ? 'pm' : 'am';
            hh = hh % 12;
            if (hh === 0) hh = 12;

            return pad2(d) + '-' + mon + '-' + yy + ' ' + hh + ':' + pad2(mm) + ' ' + ampm;
        }

        function toMoneyInt(n) {
            const v = Number(n || 0);
            const r = Math.round(v);
            return r.toLocaleString('es-CO');
        }

        function ajaxJSON(opts) {
            return $.ajax(Object.assign({
                dataType: 'json',
                contentType: 'application/json; charset=utf-8'
            }, opts));
        }

        function notifyError(msg) {
            // patrón simple: alert, consistente con pantallas existentes
            alert(msg || 'Ocurrió un error');
        }

        function buildYearOptions() {
            const now = new Date();
            const y = now.getFullYear();
            const years = [y - 1, y, y + 1];
            const $sel = $('#selYear');
            $sel.empty();
            years.forEach(yy => $sel.append($('<option>', {
                value: yy,
                text: yy
            })));
            $sel.val(String(y));
        }

        function initSelect2Dark($el, options) {
            const $modal = $el.closest('.modal');
            const dropdownParent = $modal.length ? $modal.find('.modal-content') : $(document.body);
            $el.select2(Object.assign({
                theme: 'default',
                width: '100%',
                dropdownParent
            }, options || {}));
        }

        function loadMeta() {
            return ajaxJSON({
                url: API_BASE + '&action=meta',
                method: 'GET'
            }).then(resp => {
                if (!resp || resp.ok !== true) throw new Error((resp && resp.error && resp.error.message) || 'No se pudo cargar meta');
                meta = resp.data;

                // selects modal (empresa/origen) vienen en meta
                const $emp = $('#mEmpresa');
                $emp.empty();
                (meta.empresas || []).forEach(it => $emp.append($('<option>', {
                    value: it.id,
                    text: it.nombre || it.text || it.id
                })));

                const $org = $('#mOrigen');
                $org.empty();
                (meta.origenes || []).forEach(it => $org.append($('<option>', {
                    value: it.id,
                    text: it.nombre || it.text || it.id
                })));

                initSelect2Dark($emp, {
                    placeholder: 'Seleccione...'
                });
                initSelect2Dark($org, {
                    placeholder: 'Seleccione...'
                });

                // Select2 AJAX: tercero, concepto, cuenta (reusa endpoints existentes)
                const pickResults = (resp) => {
                    const d = resp && resp.data;
                    if (!d) return [];
                    if (Array.isArray(d)) return d;
                    if (Array.isArray(d.results)) return d.results;
                    return [];
                };

                initSelect2Dark($('#mTercero'), {
                    placeholder: 'Buscar tercero...',
                    ajax: {
                        url: API_BASE + '&action=searchTerceros',
                        dataType: 'json',
                        delay: 250,
                        data: params => ({
                            q: params.term || ''
                        }),
                        processResults: data => ({
                            results: pickResults(data)
                        })
                    }
                });

                initSelect2Dark($('#mConcepto'), {
                    placeholder: 'Buscar concepto...',
                    ajax: {
                        url: API_BASE + '&action=searchConceptos',
                        dataType: 'json',
                        delay: 250,
                        data: params => ({
                            q: params.term || ''
                        }),
                        processResults: data => ({
                            results: pickResults(data)
                        })
                    }
                });

                initSelect2Dark($('#mCuenta'), {
                    placeholder: 'Buscar cuenta...',
                    ajax: {
                        url: API_BASE + '&action=searchCuentas',
                        dataType: 'json',
                        delay: 250,
                        data: params => ({
                            q: params.term || ''
                        }),
                        processResults: data => ({
                            results: pickResults(data)
                        })
                    }
                });

                return meta;
            });
        }

        function loadRecurrentes() {
            return ajaxJSON({
                url: API_BASE + '&action=recurrentes',
                method: 'GET'
            }).then(resp => {
                if (!resp || resp.ok !== true) throw new Error((resp && resp.error && resp.error.message) || 'No se pudo cargar recurrencias');
                const rows = (resp.data && resp.data.rows) ? resp.data.rows : [];
                renderRecurrentes(rows);
                return rows;
            }).catch(err => notifyError(err.message));
        }

        function renderRecurrentes(rows) {
            const $tb = $('#tblRecurrentes tbody');
            $tb.empty();

            if (!rows.length) {
                $tb.append('<tr><td colspan="12" class="text-center cpn-muted">Sin recurrencias</td></tr>');
                return;
            }

            rows.forEach(r => {
                const activoBadge = Number(r.activo) === 1 ?
                    '<span class="badge badge-success">SI</span>' :
                    '<span class="badge badge-secondary">NO</span>';

                const tr = $('<tr>');
                tr.append($('<td>').text(r.id));
                tr.append($('<td>').text(r.empresaNombre || ''));
                tr.append($('<td>').text(r.origenNombre || ''));
                tr.append($('<td>').text(r.terceroRazonSocial || r.terceroNombre || r.terceroDocumento || ''));
                tr.append($('<td>').text(r.conceptoPadreNombre ? (r.conceptoPadreNombre + ' / ' + (r.conceptoNombre || '')) : (r.conceptoNombre || '')));
                tr.append($('<td>').text((r.cuentaCode ? (r.cuentaCode + ' - ') : '') + (r.cuentaNombre || '')));
                tr.append($('<td class="text-center">').text(r.dayOfMonth || ''));
                tr.append($('<td>').text(formatDateDisplay(r.startDate)));
                tr.append($('<td>').text(formatDateDisplay(r.endDate)));
                tr.append($('<td class="text-right">').text(toMoneyInt(r.defaultAmount)));
                tr.append($('<td class="text-center">').html(activoBadge));

                const $actions = $('<td class="text-center cpn-actions">');
                const $btnSel = $('<button class="btn btn-sm btn-info mr-1">Instancias</button>').on('click', () => {
                    selectedRecurrenteId = r.id;
                    $('#instanciasHint').text('Recurrencia #' + r.id + ' — ' + (r.conceptoNombre || '') + ' / ' + (r.terceroRazonSocial || r.terceroNombre || ''));
                    loadInstancias();
                });
                const $btnEdit = $('<button class="btn btn-sm btn-primary mr-1">Editar</button>').on('click', () => {
                    openEditModal(r);
                });
                const $btnAct = $('<button class="btn btn-sm btn-warning mr-1">Activo</button>').on('click', () => {
                    const newVal = Number(r.activo) === 1 ? 0 : 1;
                    updateRecurrenteField(r.id, 'activo', newVal).then(() => loadRecurrentes());
                });
                const $btnDel = $('<button class="btn btn-sm btn-danger">Eliminar</button>').on('click', () => {
                    if (!confirm('¿Eliminar esta recurrencia y sus instancias?')) return;
                    deleteRecurrente(r.id).then(() => {
                        if (selectedRecurrenteId === r.id) {
                            selectedRecurrenteId = null;
                            $('#tblInstancias tbody').empty();
                            $('#instanciasHint').text('Seleccione una recurrencia…');
                        }
                        loadRecurrentes();
                    });
                });

                $actions.append($btnSel, $btnEdit, $btnAct, $btnDel);
                tr.append($actions);
                $tb.append(tr);
            });
        }

        function updateRecurrenteField(id, field, value) {
            return ajaxJSON({
                url: API_BASE + '&action=recurrenteUpdateField',
                method: 'POST',
                data: JSON.stringify({
                    id,
                    field,
                    value
                })
            }).then(resp => {
                if (!resp || resp.ok !== true) throw new Error((resp && resp.error && resp.error.message) || 'No se pudo actualizar');
                return resp.data;
            }).catch(err => notifyError(err.message));
        }

        function deleteRecurrente(id) {
            return ajaxJSON({
                url: API_BASE + '&action=recurrenteDelete',
                method: 'POST',
                data: JSON.stringify({
                    id
                })
            }).then(resp => {
                if (!resp || resp.ok !== true) throw new Error((resp && resp.error && resp.error.message) || 'No se pudo eliminar');
                return resp.data;
            }).catch(err => notifyError(err.message));
        }

        function createRecurrente(payload) {
            return ajaxJSON({
                url: API_BASE + '&action=recurrenteCreate',
                method: 'POST',
                data: JSON.stringify(payload)
            }).then(resp => {
                if (!resp || resp.ok !== true) throw new Error((resp && resp.error && resp.error.message) || 'No se pudo crear');
                return resp.data;
            });
        }

        function loadInstancias() {
            if (!selectedRecurrenteId) {
                $('#tblInstancias tbody').empty();
                return;
            }
            const year = Number($('#selYear').val());
            return ajaxJSON({
                url: API_BASE + '&action=instancias',
                method: 'GET',
                data: {
                    recurrenteId: selectedRecurrenteId,
                    year
                }
            }).then(resp => {
                if (!resp || resp.ok !== true) throw new Error((resp && resp.error && resp.error.message) || 'No se pudo cargar instancias');
                const rows = (resp.data && resp.data.rows) ? resp.data.rows : [];
                renderInstancias(rows);
                return rows;
            }).catch(err => notifyError(err.message));
        }

        function estadoBadge(estado) {
            const s = String(estado || '').toUpperCase();
            if (s === 'GENERADO') return '<span class="badge badge-success">GENERADO</span>';
            if (s === 'OMITIDO') return '<span class="badge badge-warning">OMITIDO</span>';
            if (s === 'ERROR') return '<span class="badge badge-danger">ERROR</span>';
            return '<span class="badge badge-secondary">PENDIENTE</span>';
        }

        function renderInstancias(rows) {
            const $tb = $('#tblInstancias tbody');
            $tb.empty();

            if (!rows.length) {
                $tb.append('<tr><td colspan="8" class="text-center cpn-muted">Sin instancias para este año</td></tr>');
                return;
            }

            rows.forEach(r => {
                const tr = $('<tr>');
                tr.append($('<td>').text(r.period || ''));
                tr.append($('<td>').text(formatDateDisplay(r.dueDate)));

                const $dueOverride = $('<input type="date" class="form-control form-control-sm" />');
                if (r.dueDateOverride) {
                    // r.dueDateOverride viene como YYYY-MM-DD
                    $dueOverride.val(String(r.dueDateOverride).slice(0, 10));
                }
                $dueOverride.on('change', () => {
                    const v = $dueOverride.val() || null;
                    updateInstanciaField(r.id, 'dueDateOverride', v).then(() => loadInstancias());
                });
                tr.append($('<td>').append($dueOverride));

                tr.append($('<td class="text-right">').text(toMoneyInt(r.defaultAmount)));

                const $amtOverride = $('<input type="number" class="form-control form-control-sm text-right" step="1" min="0" />');
                if (r.amountOverride !== null && r.amountOverride !== undefined) {
                    $amtOverride.val(String(Math.round(Number(r.amountOverride))));
                }
                $amtOverride.on('change', () => {
                    const raw = $amtOverride.val();
                    const v = (raw === '' || raw === null) ? null : Math.round(Number(raw));
                    updateInstanciaField(r.id, 'amountOverride', v).then(() => loadInstancias());
                });
                tr.append($('<td>').append($amtOverride));

                tr.append($('<td class="text-center">').html(estadoBadge(r.status)));
                {
                    const $obs = $('<td>');
                    if (r.idGastoOficial) {
                        const $a = $('<a target="_blank">').attr('href', '/gastos/detalle_gasto.php?id=' + r.idGastoOficial).text('Gasto #' + r.idGastoOficial);
                        $obs.append($a);
                        if (r.errorMsg) {
                            $obs.append($('<div class="cpn-small text-muted">').text(r.errorMsg));
                        }
                    } else {
                        $obs.text(r.errorMsg || '');
                    }
                    tr.append($obs);
                }

                const $actions = $('<td class="text-center cpn-actions">');
                const $btnOmit = $('<button class="btn btn-sm btn-warning mr-1">Omitir</button>').on('click', () => {
                    updateInstanciaField(r.id, 'status', 'OMITIDO').then(() => loadInstancias());
                });
                const $btnPend = $('<button class="btn btn-sm btn-secondary mr-1">Pendiente</button>').on('click', () => {
                    updateInstanciaField(r.id, 'status', 'PENDIENTE').then(() => loadInstancias());
                });
                const $btnGen = $('<button class="btn btn-sm btn-success mr-1">Generar gasto</button>').on('click', () => {
                    if (!confirm('¿Generar el gasto oficial para ' + (r.period || '') + '?')) return;
                    generarGasto(r.id).then(out => {
                        if (out && out.idGastoOficial) {
                            window.open('/gastos/detalle_gasto.php?id=' + out.idGastoOficial, '_blank');
                        }
                        loadInstancias();
                    });
                });

                $actions.append($btnOmit, $btnPend, $btnGen);
                tr.append($actions);

                $tb.append(tr);
            });
        }

        function updateInstanciaField(id, field, value) {
            return ajaxJSON({
                url: API_BASE + '&action=instanciaUpdateField',
                method: 'POST',
                data: JSON.stringify({
                    id,
                    field,
                    value
                })
            }).then(resp => {
                if (!resp || resp.ok !== true) throw new Error((resp && resp.error && resp.error.message) || 'No se pudo actualizar instancia');
                return resp.data;
            }).catch(err => notifyError(err.message));
        }

        function generarGasto(idInstancia) {
            return ajaxJSON({
                url: API_BASE + '&action=generarGasto',
                method: 'POST',
                data: JSON.stringify({
                    id: idInstancia
                })
            }).then(resp => {
                if (!resp || resp.ok !== true) throw new Error((resp && resp.error && resp.error.message) || 'No se pudo generar gasto');
                return resp.data;
            }).catch(err => notifyError(err.message));
        }

        function openNewModal() {
            editingRecurrenteId = null;
            $('#modalRecurrente .modal-title').text('Nueva recurrencia');
            // reset
            $('#frmRecurrente')[0].reset();
            $('#mEmpresa').val(null).trigger('change');
            $('#mOrigen').val(null).trigger('change');
            $('#mTercero').val(null).trigger('change');
            $('#mConcepto').val(null).trigger('change');
            $('#mCuenta').val(null).trigger('change');
            $('#modalRecurrente').modal('show');
        }

        function setSelect2Value($el, id, text) {
            if (!id) {
                $el.val(null).trigger('change');
                return;
            }
            const opt = new Option(text || String(id), String(id), true, true);
            $el.append(opt).trigger('change');
        }

        function openEditModal(row) {
            editingRecurrenteId = Number(row.id);
            $('#modalRecurrente .modal-title').text('Editar recurrencia #' + row.id);
            $('#frmRecurrente')[0].reset();

            $('#mEmpresa').val(String(row.idEmpresa || '')).trigger('change');
            $('#mOrigen').val(String(row.idOrigen || '')).trigger('change');

            setSelect2Value($('#mTercero'), row.idTercero, row.terceroRazonSocial || row.terceroNombre || row.terceroDocumento || '');
            setSelect2Value(
                $('#mConcepto'),
                row.idConcepto,
                (row.conceptoPadreNombre ? (row.conceptoPadreNombre + ' / ') : '') + (row.conceptoNombre || '')
            );
            setSelect2Value($('#mCuenta'), row.idCuenta, (row.cuentaCode ? (row.cuentaCode + ' - ') : '') + (row.cuentaNombre || ''));

            $('#frmRecurrente [name=dayOfMonth]').val(row.dayOfMonth || 1);
            $('#frmRecurrente [name=defaultAmount]').val(row.defaultAmount !== null && row.defaultAmount !== undefined ? Math.round(Number(row.defaultAmount)) : 0);
            $('#frmRecurrente [name=startDate]').val(row.startDate ? String(row.startDate).slice(0, 10) : '');
            $('#frmRecurrente [name=endDate]').val(row.endDate ? String(row.endDate).slice(0, 10) : '');
            $('#frmRecurrente [name=activo]').val(String(Number(row.activo) === 1 ? 1 : 0));

            $('#modalRecurrente').modal('show');
        }

        function saveFromModal() {
            const formArr = $('#frmRecurrente').serializeArray();
            const payload = {};
            formArr.forEach(it => payload[it.name] = it.value);

            payload.idEmpresa = payload.idEmpresa ? Number(payload.idEmpresa) : null;
            payload.idOrigen = payload.idOrigen ? Number(payload.idOrigen) : null;
            payload.idTercero = payload.idTercero ? Number(payload.idTercero) : null;
            payload.idConcepto = payload.idConcepto ? Number(payload.idConcepto) : null;
            payload.idCuenta = payload.idCuenta ? Number(payload.idCuenta) : null;
            payload.dayOfMonth = payload.dayOfMonth ? Number(payload.dayOfMonth) : 1;
            payload.defaultAmount = payload.defaultAmount ? Math.round(Number(payload.defaultAmount)) : 0;
            payload.activo = payload.activo !== undefined ? Number(payload.activo) : 1;
            payload.startDate = payload.startDate || null;
            payload.endDate = payload.endDate || null;

            if (!payload.idEmpresa || !payload.idOrigen || !payload.idTercero || !payload.idConcepto || !payload.idCuenta) {
                notifyError('Complete Empresa, Origen, Tercero, Concepto y Cuenta.');
                return;
            }

            if (!editingRecurrenteId) {
                createRecurrente(payload).then(() => {
                    $('#modalRecurrente').modal('hide');
                    loadRecurrentes();
                }).catch(err => notifyError(err.message));
                return;
            }

            const id = editingRecurrenteId;
            const updates = [
                ['idEmpresa', payload.idEmpresa],
                ['idOrigen', payload.idOrigen],
                ['idTercero', payload.idTercero],
                ['idConcepto', payload.idConcepto],
                ['idCuenta', payload.idCuenta],
                ['dayOfMonth', payload.dayOfMonth],
                ['defaultAmount', payload.defaultAmount],
                ['startDate', payload.startDate],
                ['endDate', payload.endDate],
                ['activo', payload.activo],
            ];

            Promise.all(updates.map(([field, value]) => updateRecurrenteField(id, field, value)))
                .then(() => {
                    $('#modalRecurrente').modal('hide');
                    loadRecurrentes();
                })
                .catch(err => notifyError(err.message));
        }

        $(document).ready(function() {
            // Evita cierres accidentales al interactuar con Select2
            $('#modalRecurrente').modal({
                backdrop: 'static',
                keyboard: false,
                show: false
            });
            buildYearOptions();

            $('#selYear').on('change', () => {
                if (selectedRecurrenteId) loadInstancias();
            });

            $('#btnNewRecurrente').on('click', () => openNewModal());
            $('#btnSaveRecurrente').on('click', () => saveFromModal());

            loadMeta().then(() => loadRecurrentes());
        });
    })();
</script>

<?php
require_once __DIR__ . '/../templates/footer.php';
?>