-- Migración integral de Gastos Fijos hacia BD contabilidad
-- Fecha: 2026-02-28
-- Objetivo:
--  1) Crear esquema integral en contabilidad
--  2) Migrar datos legacy desde admin.gastos_fijos y tablas normalizadas de admin
--  3) Dejar habilitado presupuesto mensual por item + ajustes + auditoría
--  4) Integrar ítem de nómina mensual desde nominasP.nomi_general.sueldo

START TRANSACTION;

USE contabilidad;

/* =========================================================
   1) Esquema base en contabilidad
   ========================================================= */
CREATE TABLE IF NOT EXISTS gastos_fijos_catalogo (
    id INT AUTO_INCREMENT PRIMARY KEY,
    codigo VARCHAR(60) NOT NULL,
    descripcion VARCHAR(255) NOT NULL,
    categoria VARCHAR(100) NULL,
    activo TINYINT(1) NOT NULL DEFAULT 1,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uq_gf_catalogo_codigo (codigo),
    UNIQUE KEY uq_gf_catalogo_descripcion (descripcion),
    KEY idx_gf_catalogo_activo (activo),
    KEY idx_gf_catalogo_categoria (categoria)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS gastos_fijos_periodos (
    id INT AUTO_INCREMENT PRIMARY KEY,
    catalogo_id INT NOT NULL,
    periodo CHAR(7) NOT NULL COMMENT 'YYYY-MM',
    monto_presupuestado DECIMAL(14,2) NOT NULL DEFAULT 0.00,
    rollover_anterior DECIMAL(14,2) NOT NULL DEFAULT 0.00,
    monto_ejecutado_calculado DECIMAL(14,2) NOT NULL DEFAULT 0.00,
    monto_restante DECIMAL(14,2) NOT NULL DEFAULT 0.00,
    porcentaje_uso DECIMAL(8,2) NOT NULL DEFAULT 0.00,
    cerrado TINYINT(1) NOT NULL DEFAULT 0,
    notas VARCHAR(300) NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    updated_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    UNIQUE KEY uq_gf_periodo (catalogo_id, periodo),
    KEY idx_gf_periodo_periodo (periodo),
    KEY idx_gf_periodo_cerrado (cerrado),
    CONSTRAINT fk_gf_periodo_catalogo FOREIGN KEY (catalogo_id)
        REFERENCES gastos_fijos_catalogo(id)
        ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS gastos_fijos_ajustes (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    catalogo_id INT NOT NULL,
    periodo CHAR(7) NOT NULL,
    monto_ajuste DECIMAL(14,2) NOT NULL,
    motivo VARCHAR(255) NULL,
    usuario VARCHAR(120) NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    KEY idx_gf_ajustes_catalogo_periodo (catalogo_id, periodo),
    KEY idx_gf_ajustes_created (created_at),
    CONSTRAINT fk_gf_ajustes_catalogo FOREIGN KEY (catalogo_id)
        REFERENCES gastos_fijos_catalogo(id)
        ON UPDATE CASCADE ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

CREATE TABLE IF NOT EXISTS gastos_fijos_auditoria (
    id BIGINT AUTO_INCREMENT PRIMARY KEY,
    entidad VARCHAR(60) NOT NULL,
    entidad_id BIGINT NULL,
    accion VARCHAR(40) NOT NULL,
    detalle JSON NULL,
    usuario VARCHAR(120) NULL,
    ip_origen VARCHAR(60) NULL,
    created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
    KEY idx_gf_auditoria_entidad (entidad, entidad_id),
    KEY idx_gf_auditoria_fecha (created_at)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;

/* Índices recomendados para cálculo de ejecución real */
SET @idx_gastos_grupo_fecha := (
  SELECT COUNT(*)
  FROM information_schema.statistics
  WHERE table_schema = 'contabilidad' AND table_name = 'gastos' AND index_name = 'idx_gastos_grupo_fecha'
);
SET @sql_idx_gastos := IF(@idx_gastos_grupo_fecha = 0,
  'CREATE INDEX idx_gastos_grupo_fecha ON contabilidad.gastos (grupo, fecha)',
  'SELECT 1'
);
PREPARE stmt_idx_gastos FROM @sql_idx_gastos;
EXECUTE stmt_idx_gastos;
DEALLOCATE PREPARE stmt_idx_gastos;

SET @idx_tasa_fecha := (
  SELECT COUNT(*)
  FROM information_schema.statistics
  WHERE table_schema = 'contabilidad' AND table_name = 'tasas_dolar' AND index_name = 'idx_tasas_fecha'
);
SET @sql_idx_tasas := IF(@idx_tasa_fecha = 0,
  'CREATE INDEX idx_tasas_fecha ON contabilidad.tasas_dolar (fecha)',
  'SELECT 1'
);
PREPARE stmt_idx_tasas FROM @sql_idx_tasas;
EXECUTE stmt_idx_tasas;
DEALLOCATE PREPARE stmt_idx_tasas;

/* =========================================================
   2) Migración desde esquema normalizado de admin (si existe)
   ========================================================= */
INSERT INTO contabilidad.gastos_fijos_catalogo (codigo, descripcion, categoria, activo, created_at, updated_at)
SELECT a.codigo, a.descripcion, NULL, a.activo,
       COALESCE(a.created_at, NOW()), COALESCE(a.updated_at, NOW())
FROM admin.gastos_fijos_catalogo a
LEFT JOIN contabilidad.gastos_fijos_catalogo c
    ON BINARY c.codigo = BINARY a.codigo
WHERE c.id IS NULL;

INSERT INTO contabilidad.gastos_fijos_periodos (
    catalogo_id, periodo, monto_presupuestado, rollover_anterior,
    monto_ejecutado_calculado, monto_restante, porcentaje_uso,
    cerrado, notas, created_at, updated_at
)
SELECT
    c.id AS catalogo_id,
    ap.periodo,
    ap.monto_presupuestado,
    ap.rollover_anterior,
    COALESCE(ap.monto_ejecutado_calculado, 0),
    COALESCE(ap.monto_restante, 0),
    COALESCE(ap.porcentaje_uso, 0),
    COALESCE(ap.cerrado, 0),
    NULL,
    COALESCE(ap.created_at, NOW()),
    COALESCE(ap.updated_at, NOW())
FROM admin.gastos_fijos_periodos ap
JOIN admin.gastos_fijos_catalogo ac ON ac.id = ap.catalogo_id
JOIN contabilidad.gastos_fijos_catalogo c
    ON BINARY c.codigo = BINARY ac.codigo
LEFT JOIN contabilidad.gastos_fijos_periodos cp
    ON cp.catalogo_id = c.id AND cp.periodo = ap.periodo
WHERE cp.id IS NULL;

INSERT INTO contabilidad.gastos_fijos_ajustes (catalogo_id, periodo, monto_ajuste, motivo, usuario, created_at)
SELECT
    c.id,
    aa.periodo,
    aa.monto_ajuste,
    aa.motivo,
    NULL,
    COALESCE(aa.created_at, NOW())
FROM admin.gastos_fijos_ajustes aa
JOIN admin.gastos_fijos_catalogo ac ON ac.id = aa.catalogo_id
JOIN contabilidad.gastos_fijos_catalogo c
    ON BINARY c.codigo = BINARY ac.codigo;

/* =========================================================
   3) Migración desde tabla legacy admin.gastos_fijos (si existe)
   ========================================================= */
INSERT INTO contabilidad.gastos_fijos_catalogo (codigo, descripcion, categoria, activo, created_at, updated_at)
SELECT DISTINCT
        LEFT(LOWER(REPLACE(REPLACE(TRIM(COALESCE(NULLIF(gf.descripcion,''), NULLIF(gf.nombre,''))), ' ', '_'), '-', '_')), 60) AS codigo,
        TRIM(COALESCE(NULLIF(gf.descripcion,''), NULLIF(gf.nombre,''))) AS descripcion,
        NULLIF(TRIM(gf.categoria), ''),
        CASE WHEN COALESCE(gf.activo, 1) IN (0, '0') THEN 0 ELSE 1 END,
    NOW(), NOW()
FROM admin.gastos_fijos gf
LEFT JOIN contabilidad.gastos_fijos_catalogo c
        ON BINARY c.descripcion = BINARY TRIM(COALESCE(NULLIF(gf.descripcion,''), NULLIF(gf.nombre,'')))
WHERE COALESCE(NULLIF(gf.descripcion,''), NULLIF(gf.nombre,'')) IS NOT NULL
    AND TRIM(COALESCE(NULLIF(gf.descripcion,''), NULLIF(gf.nombre,''))) <> ''
  AND c.id IS NULL;

INSERT INTO contabilidad.gastos_fijos_periodos (
    catalogo_id, periodo, monto_presupuestado, rollover_anterior,
    monto_ejecutado_calculado, monto_restante, porcentaje_uso,
    cerrado, notas, created_at, updated_at
)
SELECT
    c.id,
    DATE_FORMAT(CURDATE(), '%Y-%m') AS periodo,
        MAX(COALESCE(gf.monto_mensual,0)) AS monto_presupuestado,
    0,
        0 AS monto_ejecutado_calculado,
        MAX(COALESCE(gf.monto_mensual,0)) AS monto_restante,
    CASE
            WHEN MAX(COALESCE(gf.monto_mensual,0)) > 0
                THEN 0
      ELSE 0
    END AS porcentaje_uso,
    0,
    CONCAT('Migrado desde admin.gastos_fijos. Registros agrupados: ', COUNT(*)),
    NOW(), NOW()
FROM admin.gastos_fijos gf
JOIN contabilidad.gastos_fijos_catalogo c
        ON BINARY c.descripcion = BINARY TRIM(COALESCE(NULLIF(gf.descripcion,''), NULLIF(gf.nombre,'')))
LEFT JOIN contabilidad.gastos_fijos_periodos cp
        ON cp.catalogo_id = c.id AND cp.periodo = DATE_FORMAT(CURDATE(), '%Y-%m')
WHERE COALESCE(NULLIF(gf.descripcion,''), NULLIF(gf.nombre,'')) IS NOT NULL
    AND TRIM(COALESCE(NULLIF(gf.descripcion,''), NULLIF(gf.nombre,''))) <> ''
  AND cp.id IS NULL
GROUP BY c.id;

/* =========================================================
   4) Upsert inicial del ítem nómina mensual
   ========================================================= */
INSERT INTO contabilidad.gastos_fijos_catalogo (codigo, descripcion, categoria, activo, created_at, updated_at)
SELECT 'nomina_mensual', 'Nómina mensual (auto desde nominasP)', 'nomina', 1, NOW(), NOW()
WHERE NOT EXISTS (
    SELECT 1 FROM contabilidad.gastos_fijos_catalogo WHERE codigo = 'nomina_mensual'
);

INSERT INTO contabilidad.gastos_fijos_periodos (
    catalogo_id, periodo, monto_presupuestado, rollover_anterior,
    monto_ejecutado_calculado, monto_restante, porcentaje_uso,
    cerrado, notas, created_at, updated_at
)
SELECT
    c.id,
    DATE_FORMAT(CURDATE(), '%Y-%m') AS periodo,
    COALESCE((
        SELECT SUM(COALESCE(n.sueldo,0))
        FROM nominasP.nomi_general n
        WHERE n.estatus IS NULL OR n.estatus='' OR LOWER(n.estatus)='activo'
    ), 0),
    0,
    0,
    0,
    0,
    0,
    'Presupuesto generado por migración inicial desde nominasP.nomi_general.sueldo',
    NOW(), NOW()
FROM contabilidad.gastos_fijos_catalogo c
WHERE c.codigo = 'nomina_mensual'
ON DUPLICATE KEY UPDATE
    monto_presupuestado = VALUES(monto_presupuestado),
    updated_at = NOW();

/* =========================================================
   5) Vista de apoyo para reportes
   ========================================================= */
DROP VIEW IF EXISTS contabilidad.vw_gastos_fijos_resumen;
CREATE VIEW contabilidad.vw_gastos_fijos_resumen AS
SELECT
    c.id AS catalogo_id,
    c.codigo,
    c.descripcion,
    p.id AS periodo_id,
    p.periodo,
    p.monto_presupuestado,
    p.rollover_anterior,
    p.monto_ejecutado_calculado,
    p.monto_restante,
    p.porcentaje_uso,
    p.cerrado,
    p.updated_at
FROM contabilidad.gastos_fijos_catalogo c
JOIN contabilidad.gastos_fijos_periodos p ON p.catalogo_id = c.id;

COMMIT;

/* =========================================================
   6) Permisos RBAC sugeridos (ejecutar en chat)
   =========================================================
USE chat;

INSERT INTO rbac_permissions (module, action, min_level, description)
VALUES
('/admin/gastos_fijos.php', 'view', 5, 'Ver módulo gastos fijos'),
('/admin/gastos_fijos.php', 'create', 5, 'Crear ítems/presupuestos gastos fijos'),
('/admin/gastos_fijos.php', 'edit', 5, 'Editar ítems/presupuestos gastos fijos'),
('/admin/gastos_fijos.php', 'delete', 5, 'Eliminar ítems de gastos fijos'),
('/admin/gastos_fijos.php', 'close', 5, 'Cerrar periodo mensual gastos fijos'),
('/admin/gastos_fijos.php', 'reopen', 5, 'Reabrir periodo mensual gastos fijos'),
('/admin/gastos_fijos.php', 'adjust', 5, 'Aplicar ajustes manuales a periodos'),
('/admin/gastos_fijos.php', 'sync_nomina', 5, 'Sincronizar presupuesto de nómina')
ON DUPLICATE KEY UPDATE
  min_level = VALUES(min_level),
  description = VALUES(description),
  updated_at = CURRENT_TIMESTAMP;
*/
