<?php

require_once BASE_PATH . '/config/database.php';

class ActivityLog
{
    private PDO $db;

    public function __construct()
    {
        $this->db = (new Database())->connect();
    }

    public function transaction(callable $callback): void
    {
        $this->db->beginTransaction();

        try {
            $callback();
            $this->db->commit();
        } catch (Throwable $e) {
            if ($this->db->inTransaction()) {
                $this->db->rollBack();
            }

            throw $e;
        }
    }

    public function create(
        int $actorId,
        string $action,
        string $entityType,
        ?int $entityId,
        array $details,
        ?string $ipAddress,
        ?string $userAgent
    ): void {
        $detailsJson = json_encode(
            $details,
            JSON_UNESCAPED_UNICODE
                | JSON_UNESCAPED_SLASHES
                | JSON_THROW_ON_ERROR
        );

        $stmt = $this->db->prepare(
            'INSERT INTO activity_logs (
                actor_id, action, entity_type, entity_id,
                details_json, ip_address, user_agent
             ) VALUES (
                :actor_id, :action, :entity_type, :entity_id,
                :details_json, :ip_address, :user_agent
             )'
        );

        $stmt->execute([
            'actor_id' => $actorId,
            'action' => $action,
            'entity_type' => $entityType,
            'entity_id' => $entityId,
            'details_json' => $detailsJson,
            'ip_address' => $ipAddress !== null
                ? substr($ipAddress, 0, 45)
                : null,
            'user_agent' => $userAgent !== null
                ? substr($userAgent, 0, 500)
                : null
        ]);
    }

    public function countForAdmin(
        string $actionSearch = '',
        string $entityType = '',
        int $actorId = 0
    ): int {
        [$where, $params] = $this->buildAdminFilters(
            $actionSearch,
            $entityType,
            $actorId
        );

        $stmt = $this->db->prepare(
            "SELECT COUNT(*) FROM activity_logs l WHERE {$where}"
        );
        $stmt->execute($params);

        return (int) $stmt->fetchColumn();
    }

    public function getForAdmin(
        string $actionSearch = '',
        string $entityType = '',
        int $actorId = 0,
        int $limit = 20,
        int $offset = 0
    ): array {
        [$where, $params] = $this->buildAdminFilters(
            $actionSearch,
            $entityType,
            $actorId
        );

        $limit = max(1, $limit);
        $offset = max(0, $offset);

        $stmt = $this->db->prepare(
            "SELECT
                l.*,
                u.full_name AS actor_name,
                u.email AS actor_email
             FROM activity_logs l
             LEFT JOIN users u ON u.id = l.actor_id
             WHERE {$where}
             ORDER BY l.created_at DESC, l.id DESC
             LIMIT {$limit} OFFSET {$offset}"
        );
        $stmt->execute($params);

        return $stmt->fetchAll();
    }

    private function buildAdminFilters(
        string $actionSearch,
        string $entityType,
        int $actorId
    ): array {
        $where = '1 = 1';
        $params = [];

        if ($actionSearch !== '') {
            $where .= ' AND l.action LIKE :action_search';
            $params['action_search'] = '%' . $actionSearch . '%';
        }

        if ($entityType !== '') {
            $where .= ' AND l.entity_type = :entity_type';
            $params['entity_type'] = $entityType;
        }

        if ($actorId > 0) {
            $where .= ' AND l.actor_id = :actor_id';
            $params['actor_id'] = $actorId;
        }

        return [$where, $params];
    }
}
