#!/usr/bin/env php
<?php
/**
 * Aprobaciones del agente autonomo
 *
 * Uso:
 *   php bin/agent-approval list
 *   php bin/agent-approval list --all
 *   php bin/agent-approval show --id=3
 *   php bin/agent-approval approve --id=3 --user-id=1 --comment="Revisado"
 *   php bin/agent-approval reject  --id=3 --user-id=1 --comment="No corresponde"
 *
 * Este CLI es la contraparte humana de `?c=agentapi&a=requestApproval`. La API
 * del agente no expone la resolucion a proposito: si el agente pudiera aprobar
 * sus propias solicitudes, el control no serviria de nada.
 *
 * Aprobar NO ejecuta la operacion: marca la solicitud como aprobada y deja
 * constancia en el caso. Quien la ejecute (una persona desde la interfaz, o el
 * agente en un siguiente turno) lo hace por las vias normales, con sus propias
 * validaciones.
 */

$basePath = dirname(__DIR__);
define('BASE_PATH', $basePath . '/');

require $basePath . '/core/helpers/Env.php';
Env::load($basePath . '/.env');

$args = array_slice($argv, 1);
$command = '';
foreach ($args as $arg) {
    if (strpos($arg, '--') !== 0) {
        $command = strtolower(trim($arg));
        break;
    }
}

if ($command === '' || in_array('--help', $args, true) || in_array('-h', $args, true)) {
    echo "\nAprobaciones del agente autonomo\n\n";
    echo "Uso:\n";
    echo "  php bin/agent-approval list [--all] [--ticket=ID]\n";
    echo "  php bin/agent-approval show --id=N\n";
    echo "  php bin/agent-approval approve --id=N --user-id=N [--comment=\"...\"]\n";
    echo "  php bin/agent-approval reject  --id=N --user-id=N [--comment=\"...\"]\n\n";
    echo "Opciones:\n";
    echo "  --all           Incluye las ya resueltas (por defecto solo pendientes)\n";
    echo "  --ticket=ID     Filtra por caso\n";
    echo "  --id=N          Id de la solicitud de aprobacion\n";
    echo "  --user-id=N     Usuario humano que resuelve (obligatorio)\n";
    echo "  --comment=TEXTO Comentario de la resolucion\n";
    echo "  --tenant=KEY    Tenant a usar\n\n";
    echo "Nota: aprobar no ejecuta la operacion; la habilita y la deja registrada.\n\n";
    exit(0);
}

$getOption = function ($name, $default = '') use ($args) {
    $prefix = '--' . $name . '=';
    foreach ($args as $arg) {
        if (strpos($arg, $prefix) === 0) {
            return trim((string)substr($arg, strlen($prefix)));
        }
    }

    return $default;
};

$tenantKey = $getOption('tenant');
if ($tenantKey !== '') {
    putenv('KLEE_TENANT=' . $tenantKey);
    $_ENV['KLEE_TENANT'] = $tenantKey;
    $_SERVER['KLEE_TENANT'] = $tenantKey;
}

if (file_exists($basePath . '/vendor/autoload.php')) {
    require $basePath . '/vendor/autoload.php';
}

$fallbackAutoloadSearchPaths = array(
    'core/',
    'core/traits/',
    'core/db/',
    'core/middleware/',
    'core/attributes/',
    'core/contracts/',
    'app/models/',
    'app/controllers/',
    'core/helpers/',
    'app/config/',
);

$fallbackClassFileMap = array(
    'DB' => 'core/Db.php',
    'Database' => 'core/Db.php',
    'FORM_VALIDATE' => 'core/Formvalidate.php',
    'FormValidator' => 'core/Formvalidate.php',
);

spl_autoload_register(function ($class) use ($basePath, $fallbackAutoloadSearchPaths, $fallbackClassFileMap) {
    if (isset($fallbackClassFileMap[$class])) {
        $mappedPath = $basePath . '/' . $fallbackClassFileMap[$class];
        if (file_exists($mappedPath)) {
            require_once $mappedPath;
            return;
        }
    }

    foreach ($fallbackAutoloadSearchPaths as $relativePath) {
        $classPath = $basePath . '/' . $relativePath . $class . '.php';
        if (file_exists($classPath)) {
            require_once $classPath;
            return;
        }
    }
}, true, true);

if (file_exists($basePath . '/app/config/Config.php')) {
    require $basePath . '/app/config/Config.php';
}
if (file_exists($basePath . '/app/config/ConfigEnv.php')) {
    require $basePath . '/app/config/ConfigEnv.php';
}

if (class_exists('TenantContext')) {
    TenantContext::bootstrap();
}
if (class_exists('Controller')) {
    Controller::syncConfigFromEnv();
}
if (class_exists('Config')) {
    @date_default_timezone_set(Config::getTimezone());
}
if (session_status() === PHP_SESSION_NONE) {
    @session_start();
}

if (!class_exists('AgentAprobacionesModel')) {
    echo "[error] AgentAprobacionesModel no disponible. Ejecuta: composer dump-autoload\n";
    exit(2);
}

/** Formato compacto de una fila de aprobacion. */
$printRow = function ($fila) {
    printf(
        "  %-4s %-8s %-18s %-11s %-19s %s\n",
        (int)$fila['Id'],
        (int)$fila['TicketId'],
        mb_substr((string)$fila['Operacion'], 0, 17),
        (string)$fila['EstadoAprobacion'],
        (string)$fila['FechaRegistro'],
        mb_substr((string)($fila['AgenteExterno'] ?? '-'), 0, 20)
    );
};

$connection = Database::getConnection('klee');

switch ($command) {
    case 'list':
        $soloPendientes = !in_array('--all', $args, true);
        $ticketId = (int)$getOption('ticket', '0');

        $sql = 'SELECT * FROM tickets_agente_aprobaciones WHERE Estado = 1';
        $bindings = array();

        if ($soloPendientes) {
            $sql .= ' AND EstadoAprobacion = ?';
            $bindings[] = AgentAprobacionesModel::ESTADO_PENDIENTE;
        }
        if ($ticketId > 0) {
            $sql .= ' AND TicketId = ?';
            $bindings[] = $ticketId;
        }
        $sql .= ' ORDER BY Id DESC LIMIT 200';

        $statement = $connection->prepare($sql);
        $statement->execute($bindings);
        $filas = $statement->fetchAll(PDO::FETCH_ASSOC);

        if (empty($filas)) {
            echo "\n" . ($soloPendientes
                ? "No hay solicitudes de aprobacion pendientes.\n"
                : "No hay solicitudes de aprobacion registradas.\n") . "\n";
            exit(0);
        }

        echo "\n" . ($soloPendientes ? "Solicitudes PENDIENTES" : "Solicitudes de aprobacion") . "\n";
        echo str_repeat('-', 92) . "\n";
        printf("  %-4s %-8s %-18s %-11s %-19s %s\n", 'Id', 'Caso', 'Operacion', 'Estado', 'Solicitada', 'Agente');
        echo str_repeat('-', 92) . "\n";
        foreach ($filas as $fila) {
            $printRow($fila);
        }
        echo str_repeat('-', 92) . "\n";
        echo "  Detalle: php bin/agent-approval show --id=N\n\n";
        break;

    case 'show':
        $id = (int)$getOption('id', '0');
        if ($id <= 0) {
            echo "[error] Falta --id.\n";
            exit(1);
        }

        $fila = AgentAprobacionesModel::getAprobacionById($id);
        if (!is_array($fila)) {
            echo "[error] La solicitud $id no existe.\n";
            exit(1);
        }

        echo "\nSolicitud de aprobacion #" . (int)$fila['Id'] . "\n";
        echo str_repeat('-', 76) . "\n";
        echo "  Caso:          " . (int)$fila['TicketId'] . "\n";
        echo "  Operacion:     " . (string)$fila['Operacion'] . "\n";
        echo "  Estado:        " . (string)$fila['EstadoAprobacion'] . "\n";
        echo "  Riesgo:        " . (string)($fila['RiesgoDeclarado'] ?? '-') . "\n";
        echo "  Agente:        " . (string)($fila['AgenteExterno'] ?? '-') . "\n";
        echo "  Solicitada:    " . (string)($fila['FechaRegistro'] ?? '-') . "\n";
        if (!empty($fila['ResueltaEn'])) {
            echo "  Resuelta:      " . (string)$fila['ResueltaEn']
                . " por usuario " . (int)$fila['ResueltaPorUsuarioId'] . "\n";
            echo "  Comentario:    " . (string)($fila['ComentarioResolucion'] ?? '-') . "\n";
        }
        echo str_repeat('-', 76) . "\n";
        echo "  Justificacion del agente:\n";
        echo "  " . wordwrap((string)($fila['Justificacion'] ?? '-'), 70, "\n  ") . "\n";

        if (!empty($fila['PayloadJson'])) {
            echo str_repeat('-', 76) . "\n";
            echo "  Payload propuesto:\n";
            $payload = json_decode((string)$fila['PayloadJson'], true);
            echo "  " . str_replace(
                "\n",
                "\n  ",
                json_encode($payload, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE)
            ) . "\n";
        }
        echo str_repeat('-', 76) . "\n\n";
        break;

    case 'approve':
    case 'reject':
        $id = (int)$getOption('id', '0');
        $usuarioId = (int)$getOption('user-id', '0');
        $comentario = $getOption('comment');

        if ($id <= 0) {
            echo "[error] Falta --id. Consulte las pendientes con: php bin/agent-approval list\n";
            exit(1);
        }

        if ($usuarioId <= 0) {
            echo "[error] Falta --user-id: debe quedar registrado quien resuelve la solicitud.\n";
            exit(1);
        }

        // El resolutor debe ser una persona con permisos de la mesa. Sin esta
        // comprobacion, cualquier Id numerico serviria para "aprobar".
        if (!TicketsModel::isSupportUser($usuarioId)) {
            echo "[error] El usuario $usuarioId no es personal de soporte de la mesa.\n";
            exit(1);
        }

        $aprobada = ($command === 'approve');
        $resultado = AgentAprobacionesModel::resolver($id, $aprobada, $usuarioId, $comentario);

        if (empty($resultado['ok'])) {
            echo '[error] ' . (string)$resultado['message'] . "\n";
            exit(1);
        }

        // Dejar constancia en el caso: la decision humana debe ser visible en
        // el historial del ticket, no solo en esta tabla.
        $fila = AgentAprobacionesModel::getAprobacionById($id);
        if (is_array($fila)) {
            $ticketId = (int)$fila['TicketId'];
            $etiqueta = $aprobada ? 'APROBADA' : 'RECHAZADA';

            try {
                TicketsModel::addMessage(
                    $ticketId,
                    array(
                        'TipoMensaje' => 'NotaInterna',
                        'Contenido' => '<p><strong>Solicitud del agente ' . $etiqueta . '</strong></p>'
                            . '<p>Operacion: ' . htmlspecialchars((string)$fila['Operacion'], ENT_QUOTES, 'UTF-8') . '</p>'
                            . ($comentario !== ''
                                ? '<p>Comentario: ' . htmlspecialchars($comentario, ENT_QUOTES, 'UTF-8') . '</p>'
                                : ''),
                    ),
                    $usuarioId,
                    '',
                    false
                );

                TicketsModel::recordEvent(
                    $ticketId,
                    'AprobacionResuelta',
                    'Solicitud del agente ' . $etiqueta . ': ' . (string)$fila['Operacion'],
                    array(
                        'aprobacion_id' => $id,
                        'estado' => (string)$resultado['estado'],
                        'resuelta_por' => $usuarioId,
                    ),
                    $usuarioId
                );
            } catch (Throwable $exception) {
                echo "[aviso] La solicitud se resolvio, pero no fue posible registrarla en el caso: "
                    . $exception->getMessage() . "\n";
            }
        }

        echo "\nSolicitud #$id " . ($aprobada ? 'aprobada' : 'rechazada') . ".\n";
        if ($aprobada) {
            echo "La operacion NO se ejecuto: queda habilitada para que la aplique una persona\n";
            echo "desde la mesa, o el agente en un siguiente turno por las vias normales.\n";
        }
        echo "\n";
        break;

    default:
        echo "[error] Comando desconocido: " . $command . "\n";
        echo "Comandos validos: list, show, approve, reject. Use --help para el detalle.\n";
        exit(1);
}

exit(0);
