<?php
/**
 * calcular_regalias.php
 * Calcula las regalías de TODOS los distribuidores calificados para un mes/año dado
 * e inserta los registros en la tabla regs2.
 *
 * Método: POST
 * Body JSON: { "mes": 2, "anio": 2026 }
 * Auth: Bearer token (admin_sessions)
 *
 * Estructura de regs2:
 *   idreg, id_inver, calificados, primera, segunda, tercera, cuarta,
 *   total, _real, apagar, fechap, cd, status, impuestos, pagado,
 *   fechaf, llamada, observaciones, puntos, niveles
 */

header('Content-Type: application/json; charset=utf-8');
header('Access-Control-Allow-Origin: *');
header('Access-Control-Allow-Methods: POST, OPTIONS');
header('Access-Control-Allow-Headers: Content-Type, Authorization');

if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(200); exit; }

// Aumentar tiempo de ejecución para redes grandes
set_time_limit(300);
ini_set('memory_limit', '256M');

require_once __DIR__ . '/../config.php';

// ── Autenticación admin ─────────────────────────────────────────────────────
$headers    = function_exists('getallheaders') ? getallheaders() : [];
$authHeader = $headers['Authorization'] ?? $headers['authorization'] ?? '';
if (!$authHeader && !empty($_SERVER['HTTP_AUTHORIZATION'])) {
    $authHeader = $_SERVER['HTTP_AUTHORIZATION'];
} elseif (!$authHeader && !empty($_SERVER['REDIRECT_HTTP_AUTHORIZATION'])) {
    $authHeader = $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
}

if (!preg_match('/Bearer\s+(.+)/i', $authHeader, $m)) {
    http_response_code(401);
    echo json_encode(['success' => false, 'message' => 'Token requerido']);
    exit;
}
$adminToken = trim($m[1]);

$db  = getDB();
$now = date('Y-m-d H:i:s');

$stmtSess = $db->prepare(
    "SELECT s.idusuarios_sist FROM admin_sessions s
     WHERE s.token = ? AND s.expira > ? LIMIT 1"
);
$stmtSess->execute([$adminToken, $now]);
if (!$stmtSess->fetch()) {
    http_response_code(401);
    echo json_encode(['success' => false, 'message' => 'Sesión expirada o inválida']);
    exit;
}

// ── Parámetros ──────────────────────────────────────────────────────────────
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    echo json_encode(['success' => false, 'message' => 'Método no permitido']);
    exit;
}

$body = json_decode(file_get_contents('php://input'), true);
$mes  = isset($body['mes'])  ? (int)$body['mes']  : 0;
$anio = isset($body['anio']) ? (int)$body['anio'] : 0;

if ($mes < 1 || $mes > 12 || $anio < 2020 || $anio > 2100) {
    http_response_code(400);
    echo json_encode(['success' => false, 'message' => 'Mes o año inválido']);
    exit;
}

$mesInicio    = sprintf('%04d-%02d-01', $anio, $mes);
$mesFin       = date('Y-m-t', strtotime($mesInicio));
$fechaCalculo = date('Y-m-d');

$MESES_ES = [
    1=>'Enero',2=>'Febrero',3=>'Marzo',4=>'Abril',5=>'Mayo',6=>'Junio',
    7=>'Julio',8=>'Agosto',9=>'Septiembre',10=>'Octubre',11=>'Noviembre',12=>'Diciembre'
];
$periodo = ($MESES_ES[$mes] ?? $mes) . ' ' . $anio;

// ── Constantes del plan de compensación ────────────────────────────────────
define('MAX_NIVELES', 18);
define('UMBRAL_BAJO',  624);
define('UMBRAL_MEDIO', 1500);

$PORCENTAJES = [
    1=>0.10, 2=>0.17, 3=>0.17, 4=>0.17, 5=>0.01,
    6=>0.01, 7=>0.01, 8=>0.01, 9=>0.01, 10=>0.01,
    11=>0.01,12=>0.01,13=>0.01,14=>0.01,15=>0.01,
    16=>0.01,17=>0.01,18=>0.01,
];

// ── Precarga: puntos propios de todos los distribuidores en el período ──────
$stmtPuntos = $db->prepare(
    "SELECT t.inversionista_id_inver AS id_inver,
            COALESCE(SUM(d.puntos), 0) AS puntos
     FROM transacciones t
     JOIN depositos d ON d.transacciones_idtransacciones = t.idtransacciones
     WHERE t.fechat BETWEEN ? AND ?
     GROUP BY t.inversionista_id_inver"
);
$stmtPuntos->execute([$mesInicio, $mesFin]);
$puntosPorId = [];
foreach ($stmtPuntos->fetchAll(PDO::FETCH_ASSOC) as $row) {
    $puntosPorId[(int)$row['id_inver']] = (float)$row['puntos'];
}

// ── Precarga: árbol de patrocinadores (idprom) ──────────────────────────────
$stmtArbol = $db->query("SELECT id_inver, idprom FROM inversionista");
$hijosDeId  = []; // idprom → [id_inver, ...]
foreach ($stmtArbol->fetchAll(PDO::FETCH_ASSOC) as $row) {
    $id   = (int)$row['id_inver'];
    $prom = (int)($row['idprom'] ?? 0);
    if ($prom > 0) {
        $hijosDeId[$prom][] = $id;
    }
}

// ── Solo procesar distribuidores que tienen puntos >= UMBRAL_BAJO ───────────
$candidatos = array_keys(array_filter($puntosPorId, fn($p) => $p >= UMBRAL_BAJO));

if (empty($candidatos)) {
    echo json_encode(['success' => false, 'message' => 'No hay distribuidores calificados para ese período']);
    exit;
}

// ── Eliminar registros previos del mismo día ─────────────────────────────────
$db->prepare("DELETE FROM regs2 WHERE fechap = ? AND cd = 0")->execute([$fechaCalculo]);

// ── Preparar INSERT ──────────────────────────────────────────────────────────
$stmtIns = $db->prepare(
    "INSERT INTO regs2
        (id_inver, calificados, primera, segunda, tercera, cuarta,
         total, _real, apagar, fechap, cd, status, impuestos, pagado, puntos, niveles)
     VALUES
        (:id_inver, :calificados, :primera, :segunda, :tercera, :cuarta,
         :total, :_real, :apagar, :fechap, 0, 0, :impuestos, :pagado, :puntos, :niveles)"
);

$insertados  = 0;
$errores     = 0;
$totalAPagar = 0.0;

foreach ($candidatos as $idinv) {
    $idinv         = (int)$idinv;
    $puntosPropios = $puntosPorId[$idinv] ?? 0.0;

    // Calificación propia
    if ($puntosPropios < UMBRAL_BAJO) continue;

    $esParcial = ($puntosPropios < UMBRAL_MEDIO);

    // BFS para obtener puntos por nivel y directos calificados
    $currentLevel = [$idinv];
    $visitados    = [$idinv => true];
    $puntosNivel  = [];
    $directos624  = 0;
    $directos1500 = 0;

    for ($nivel = 1; $nivel <= MAX_NIVELES; $nivel++) {
        if (empty($currentLevel)) break;
        $nextLevel   = [];
        $totalPuntos = 0.0;

        foreach ($currentLevel as $pid) {
            if (empty($hijosDeId[$pid])) continue;
            foreach ($hijosDeId[$pid] as $hijo) {
                if (isset($visitados[$hijo])) continue;
                $visitados[$hijo] = true;
                $nextLevel[]      = $hijo;
                $pts              = $puntosPorId[$hijo] ?? 0.0;
                $totalPuntos     += $pts;

                if ($nivel === 1) {
                    if ($pts >= UMBRAL_BAJO)  $directos624++;
                    if ($pts >= UMBRAL_MEDIO) $directos1500++;
                }
            }
        }

        if ($totalPuntos > 0) {
            $puntosNivel[$nivel] = $totalPuntos;
        }
        $currentLevel = $nextLevel;
    }

    // Niveles abiertos
    if ($esParcial) {
        $nivelesAbiertos = ($directos624 >= 1) ? 1 : 0;
    } else {
        $nivelesBase = $directos624;
        if ($directos1500 >= 3) {
            $nivelesEspecial = 5;
        } elseif ($directos1500 >= 2) {
            $nivelesEspecial = 3;
        } else {
            $nivelesEspecial = 0;
        }
        $nivelesAbiertos = min(max($nivelesBase, $nivelesEspecial), MAX_NIVELES);
    }

    if ($nivelesAbiertos === 0) continue;

    // Calcular ganancias por nivel
    $totalGenerado = 0.0;
    $totalRecibir  = 0.0;
    $primera = 0.0; $segunda = 0.0; $tercera = 0.0; $cuarta = 0.0;

    for ($n = 1; $n <= MAX_NIVELES; $n++) {
        $pts      = $puntosNivel[$n] ?? 0.0;
        $pct      = $PORCENTAJES[$n] ?? 0.01;
        $generado = $pts * $pct;
        $recibir  = ($n <= $nivelesAbiertos) ? $generado : 0.0;
        $totalGenerado += $generado;
        $totalRecibir  += $recibir;
        if ($n === 1) $primera = $recibir;
        if ($n === 2) $segunda = $recibir;
        if ($n === 3) $tercera = $recibir;
        if ($n === 4) $cuarta  = $recibir;
    }

    if ($totalRecibir <= 0) continue;

    $apagar    = round($totalRecibir, 2);
    $impuestos = round($apagar * 0.07, 2);
    $pagado    = round($apagar - $impuestos, 2);

    try {
        $stmtIns->execute([
            ':id_inver'   => $idinv,
            ':calificados'=> $directos624,
            ':primera'    => round($primera, 2),
            ':segunda'    => round($segunda, 2),
            ':tercera'    => round($tercera, 2),
            ':cuarta'     => round($cuarta, 2),
            ':total'      => round($totalGenerado, 2),
            ':_real'      => $apagar,
            ':apagar'     => $apagar,
            ':fechap'     => $fechaCalculo,
            ':impuestos'  => $impuestos,
            ':pagado'     => $pagado,
            ':puntos'     => (int)round($puntosPropios),
            ':niveles'    => $nivelesAbiertos,
        ]);
        $insertados++;
        $totalAPagar += $apagar;
    } catch (Throwable $e) {
        $errores++;
        error_log("calcular_regalias error id_inver=$idinv: " . $e->getMessage());
    }
}

// Eliminar archivo temporal de diagnóstico si existe
@unlink(__DIR__ . '/check_db_tmp.php');

echo json_encode([
    'success'       => true,
    'periodo'       => $periodo,
    'mes'           => $mes,
    'anio'          => $anio,
    'insertados'    => $insertados,
    'errores'       => $errores,
    'total_a_pagar' => round($totalAPagar, 2),
    'fechap'        => $fechaCalculo,
], JSON_UNESCAPED_UNICODE);
