<?php
class ActivoController {
    public static function index(): void {
        $payload = AuthMiddleware::verificar();
        $db = getDB();
        $page = max(1, (int)($_GET['page'] ?? 1));
        $perPage = min(100, max(1, (int)($_GET['per_page'] ?? 20)));
        $offset = ($page - 1) * $perPage;

        $where = ["1=1"];
        $params = [];

        if (!empty($_GET['tipo'])) { $where[] = "a.tipo = ?"; $params[] = $_GET['tipo']; }
        if (!empty($_GET['estado'])) { $where[] = "a.estado = ?"; $params[] = $_GET['estado']; }
        if (!empty($_GET['buscar'])) {
            $s = '%' . $_GET['buscar'] . '%';
            $where[] = "(a.codigo_activo LIKE ? OR a.marca LIKE ? OR a.modelo LIKE ? OR a.serial LIKE ? OR a.hostname LIKE ?)";
            $params = array_merge($params, [$s, $s, $s, $s, $s]);
        }

        // Filtro por usuario asignado (para admin/tecnico al crear tickets)
        if (!empty($_GET['usuario_id'])) {
            $where[] = "a.usuario_asignado_id = ?";
            $params[] = (int)$_GET['usuario_id'];
        } elseif ($payload['rol'] === 'usuario') {
            $where[] = "a.usuario_asignado_id = ?";
            $params[] = $payload['sub'];
        }

        $whereStr = implode(' AND ', $where);
        $countStmt = $db->prepare("SELECT COUNT(*) FROM activos a WHERE $whereStr");
        $countStmt->execute($params);
        $total = (int)$countStmt->fetchColumn();

        $sql = "SELECT a.*, u.nombre_completo as asignado_nombre
                FROM activos a
                LEFT JOIN usuarios u ON a.usuario_asignado_id = u.id
                WHERE $whereStr ORDER BY a.created_at DESC LIMIT $perPage OFFSET $offset";
        $stmt = $db->prepare($sql);
        $stmt->execute($params);

        Response::paginated($stmt->fetchAll(), $total, $page, $perPage);
    }

    public static function crear(): void {
        $payload = AuthMiddleware::verificar();
        RoleMiddleware::requireTecnico($payload);
        $body = Validator::getBody();
        Validator::make($body)->required('tipo', 'marca', 'modelo')->validate();

        $db = getDB();
        $prefix = strtoupper(substr($body['tipo'], 0, 3));
        $count = (int)$db->query("SELECT COUNT(*) FROM activos WHERE tipo = '{$body['tipo']}'")->fetchColumn();
        $codigo = $prefix . '-' . str_pad($count + 1, 4, '0', STR_PAD_LEFT);

        $stmt = $db->prepare("INSERT INTO activos (codigo_activo, tipo, marca, modelo, serial, hostname, estado, ubicacion, fecha_compra, costo_adquisicion, proveedor, notas, usuario_asignado_id, direccion_ip, direccion_mac, sistema_operativo) VALUES (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)");
        $stmt->execute([
            $codigo, $body['tipo'], $body['marca'], $body['modelo'],
            $body['serial'] ?? $body['numero_serie'] ?? null,
            $body['hostname'] ?? null,
            $body['estado'] ?? 'activo',
            $body['ubicacion'] ?? null,
            $body['fecha_compra'] ?? null,
            $body['costo_adquisicion'] ?? $body['valor_compra'] ?? null,
            $body['proveedor'] ?? null,
            $body['notas'] ?? null,
            $body['usuario_asignado_id'] ?? $body['asignado_a_id'] ?? null,
            $body['direccion_ip'] ?? $body['ip_address'] ?? null,
            $body['direccion_mac'] ?? $body['mac_address'] ?? null,
            $body['sistema_operativo'] ?? $body['so'] ?? null
        ]);

        Response::created(['id' => (int)$db->lastInsertId(), 'codigo_activo' => $codigo]);
    }

    public static function ver(int $id): void {
        $payload = AuthMiddleware::verificar();
        $db = getDB();
        $stmt = $db->prepare("SELECT a.*, u.nombre_completo as usuario_asignado_nombre
            FROM activos a 
            LEFT JOIN usuarios u ON a.usuario_asignado_id = u.id 
            WHERE a.id = ?");
        $stmt->execute([$id]);
        $activo = $stmt->fetch();
        if (!$activo) Response::notFound('Activo no encontrado');

        // Hardware
        $hwStmt = $db->prepare("SELECT * FROM activo_hardware WHERE activo_id = ?");
        $hwStmt->execute([$id]);
        $activo['hardware'] = $hwStmt->fetch() ?: null;

        // Software
        $swStmt = $db->prepare("SELECT nombre_software, version, editor, tamano_mb FROM activo_software WHERE activo_id = ? ORDER BY nombre_software");
        $swStmt->execute([$id]);
        $activo['software'] = $swStmt->fetchAll();

        // Timeline
        $tlStmt = $db->prepare("SELECT t.*, u.nombre_completo as usuario_nombre FROM activo_timeline t LEFT JOIN usuarios u ON t.usuario_id = u.id WHERE t.activo_id = ? ORDER BY t.created_at DESC LIMIT 20");
        $tlStmt->execute([$id]);
        $activo['timeline'] = $tlStmt->fetchAll();

        // Última telemetría
        $telStmt = $db->prepare("SELECT cpu_uso_pct, ram_uso_pct, disco_uso_pct, temp_cpu, uptime_seconds, procesos_activos, created_at FROM telemetria WHERE activo_id = ? ORDER BY created_at DESC LIMIT 1");
        $telStmt->execute([$id]);
        $activo['telemetria_actual'] = $telStmt->fetch() ?: null;

        // Tickets relacionados
        $tStmt = $db->prepare("SELECT id, numero_ticket, titulo, estado, prioridad, created_at FROM tickets WHERE activo_id = ? ORDER BY created_at DESC LIMIT 10");
        $tStmt->execute([$id]);
        $activo['tickets'] = $tStmt->fetchAll();

        // Mantenimientos
        try {
            $mStmt = $db->prepare("SELECT id, titulo, tipo, estado, fecha_programada FROM mantenimientos WHERE activo_id = ? ORDER BY fecha_programada DESC LIMIT 10");
            $mStmt->execute([$id]);
            $activo['mantenimientos'] = $mStmt->fetchAll();
        } catch (\Exception $e) {
            $activo['mantenimientos'] = [];
        }

        Response::success($activo);
    }

    public static function actualizar(int $id): void {
        $payload = AuthMiddleware::verificar();
        RoleMiddleware::requireTecnico($payload);
        $body = Validator::getBody();
        $db = getDB();

        $allowed = ['tipo','marca','modelo','serial','hostname','estado','ubicacion','fecha_compra','costo_adquisicion','proveedor','notas','usuario_asignado_id','direccion_ip','direccion_mac','sistema_operativo'];
        $fields = []; $params = [];
        foreach ($allowed as $f) {
            if (array_key_exists($f, $body)) { $fields[] = "$f = ?"; $params[] = $body[$f]; }
        }
        if (empty($fields)) Response::error('Nada que actualizar');

        $fields[] = "updated_at = NOW()";
        $params[] = $id;
        $db->prepare("UPDATE activos SET " . implode(', ', $fields) . " WHERE id = ?")->execute($params);
        Response::success(null, 'Activo actualizado');
    }

    public static function asignar(int $id): void {
        $payload = AuthMiddleware::verificar();
        RoleMiddleware::requireTecnico($payload);
        $body = Validator::getBody();
        $db = getDB();

        $usuarioId = $body['usuario_id'] ?? null;
        $db->prepare("UPDATE activos SET usuario_asignado_id = ?, updated_at = NOW() WHERE id = ?")->execute([$usuarioId, $id]);

        // Registrar en timeline
        $nombreUsuario = 'Nadie';
        if ($usuarioId) {
            $u = $db->prepare("SELECT nombre_completo FROM usuarios WHERE id = ?");
            $u->execute([$usuarioId]);
            $nombreUsuario = $u->fetchColumn() ?: "Usuario #$usuarioId";
        }

        try {
            $db->prepare("INSERT INTO activo_timeline (activo_id, usuario_id, tipo_evento, titulo, descripcion) VALUES (?,?,?,?,?)")
                ->execute([$id, $payload['sub'], 'asignacion', "Asignado a $nombreUsuario", "Activo asignado a $nombreUsuario por " . ($payload['nombre'] ?? 'Admin')]);
        } catch (Exception $e) {}

        try {
            $db->prepare("INSERT INTO activo_historial (activo_id, usuario_id, accion, detalle) VALUES (?,?,?,?)")
                ->execute([$id, $payload['sub'], 'asignacion', "Asignado a $nombreUsuario"]);
        } catch (Exception $e) {}

        Response::success(null, 'Activo asignado');
    }

    public static function timeline(int $id): void {
        $payload = AuthMiddleware::verificar();
        $db = getDB();
        try {
            $stmt = $db->prepare("SELECT h.*, u.nombre_completo as usuario_nombre FROM activo_historial h LEFT JOIN usuarios u ON h.usuario_id = u.id WHERE h.activo_id = ? ORDER BY h.created_at DESC LIMIT 50");
            $stmt->execute([$id]);
            Response::success($stmt->fetchAll());
        } catch (Exception $e) {
            Response::success([]);
        }
    }

    // =============================================
    // BITÁCORA DEL ACTIVO
    // =============================================

    /**
     * GET /activos/{id}/bitacora — Listar bitácora de un activo
     */
    public static function bitacora(int $id): void {
        $payload = AuthMiddleware::verificar();
        RoleMiddleware::requireTecnico($payload);
        $db = getDB();

        // Verificar que el activo existe
        $stmt = $db->prepare("SELECT id FROM activos WHERE id = ?");
        $stmt->execute([$id]);
        if (!$stmt->fetch()) Response::notFound('Activo no encontrado');

        $stmt = $db->prepare("
            SELECT b.*,
                u.nombre_completo AS usuario_nombre,
                tp.nombre_completo AS tomado_por_nombre
            FROM activo_bitacora b
            LEFT JOIN usuarios u  ON b.usuario_id    = u.id
            LEFT JOIN usuarios tp ON b.tomado_por_id = tp.id
            WHERE b.activo_id = ?
            ORDER BY b.created_at DESC
            LIMIT 100
        ");
        $stmt->execute([$id]);
        Response::success($stmt->fetchAll());
    }

    /**
     * POST /activos/{id}/bitacora — Registrar entrada en bitácora
     */
    public static function registrarBitacora(int $id): void {
        $payload = AuthMiddleware::verificar();
        RoleMiddleware::requireTecnico($payload);
        $db = getDB();

        // Verificar activo
        $stmt = $db->prepare("SELECT id, codigo_activo FROM activos WHERE id = ?");
        $stmt->execute([$id]);
        $activo = $stmt->fetch();
        if (!$activo) Response::notFound('Activo no encontrado');

        $data = json_decode(file_get_contents('php://input'), true) ?? [];

        $v = new Validator($data);
        $v->required('titulo', 'Título')->maxLength('titulo', 255);
        $v->inList('tipo_registro', ['cambio','intervencion','mantenimiento','asignacion','observacion','creacion']);
        $v->validate();

        $tipoRegistro = $data['tipo_registro'] ?? 'observacion';
        $tomadoPorId  = !empty($data['tomado_por_id']) ? (int)$data['tomado_por_id'] : null;

        // Si es intervención, el tomado_por puede ser el mismo usuario que registra
        if ($tipoRegistro === 'intervencion' && !$tomadoPorId) {
            $tomadoPorId = (int)$payload['sub'];
        }

        $db->prepare("
            INSERT INTO activo_bitacora
                (activo_id, usuario_id, tipo_registro, titulo, descripcion,
                 campo_cambiado, valor_anterior, valor_nuevo,
                 tomado_por_id, costo, duracion_min)
            VALUES (?,?,?,?,?,?,?,?,?,?,?)
        ")->execute([
            $id,
            (int)$payload['sub'],
            $tipoRegistro,
            trim($data['titulo']),
            $data['descripcion']    ?? null,
            $data['campo_cambiado'] ?? null,
            $data['valor_anterior'] ?? null,
            $data['valor_nuevo']    ?? null,
            $tomadoPorId,
            !empty($data['costo'])        ? floatval($data['costo'])       : null,
            !empty($data['duracion_min']) ? intval($data['duracion_min'])  : null,
        ]);

        // Reflejar también en la timeline existente
        try {
            $db->prepare("
                INSERT INTO activo_timeline (activo_id, usuario_id, tipo_evento, titulo, descripcion, costo)
                VALUES (?,?,?,?,?,?)
            ")->execute([
                $id, (int)$payload['sub'], $tipoRegistro,
                $data['titulo'],
                $data['descripcion'] ?? null,
                !empty($data['costo']) ? floatval($data['costo']) : null
            ]);
        } catch (\Exception $e) {}

        Response::created(null, 'Registro agregado a la bitácora');
    }

    /**
     * PUT /activos/{id}/bitacora/{entryId} — Actualizar una entrada de bitácora
     */
    public static function actualizarBitacora(int $id, int $entryId): void {
        $payload = AuthMiddleware::verificar();
        RoleMiddleware::requireTecnico($payload);
        $db = getDB();

        $stmt = $db->prepare("SELECT * FROM activo_bitacora WHERE id = ? AND activo_id = ?");
        $stmt->execute([$entryId, $id]);
        if (!$stmt->fetch()) Response::notFound('Entrada no encontrada');

        $data = json_decode(file_get_contents('php://input'), true) ?? [];
        $campos = []; $valores = [];

        $permitidos = ['titulo','descripcion','campo_cambiado','valor_anterior','valor_nuevo','tomado_por_id','costo','duracion_min'];
        foreach ($permitidos as $f) {
            if (array_key_exists($f, $data)) {
                $campos[]  = "$f = ?";
                $valores[] = $data[$f];
            }
        }
        if (empty($campos)) Response::error('Sin campos para actualizar');

        $valores[] = $entryId;
        $db->prepare("UPDATE activo_bitacora SET " . implode(', ', $campos) . " WHERE id = ?")->execute($valores);
        Response::success(null, 'Entrada actualizada');
    }

    /**
     * DELETE /activos/{id}/bitacora/{entryId} — Solo admin puede eliminar entradas
     */
    public static function eliminarBitacora(int $id, int $entryId): void {
        $payload = AuthMiddleware::verificar();
        RoleMiddleware::requireAdmin($payload);
        $db = getDB();

        $stmt = $db->prepare("DELETE FROM activo_bitacora WHERE id = ? AND activo_id = ?");
        $stmt->execute([$entryId, $id]);
        if ($stmt->rowCount() === 0) Response::notFound('Entrada no encontrada');
        Response::success(null, 'Entrada eliminada');
    }

    /**
     * Auto-registrar cambios al actualizar un activo
     */
    private static function registrarCambiosAutomaticos(PDO $db, int $activoId, int $userId, array $datosViejos, array $datosNuevos): void {
        $etiquetas = [
            'estado'             => 'Estado',
            'usuario_asignado_id'=> 'Asignado a',
            'ubicacion'          => 'Ubicación',
            'hostname'           => 'Hostname',
            'direccion_ip'       => 'IP',
        ];
        foreach ($etiquetas as $campo => $etiqueta) {
            if (isset($datosNuevos[$campo]) && (string)$datosViejos[$campo] !== (string)$datosNuevos[$campo]) {
                $db->prepare("
                    INSERT INTO activo_bitacora (activo_id, usuario_id, tipo_registro, titulo, campo_cambiado, valor_anterior, valor_nuevo)
                    VALUES (?,?,?,?,?,?,?)
                ")->execute([
                    $activoId, $userId, 'cambio',
                    "Cambio de $etiqueta",
                    $campo, $datosViejos[$campo] ?? '', $datosNuevos[$campo] ?? ''
                ]);
            }
        }
    }

}

// Note: closing brace of class moved to end of file
