<?php

declare(strict_types=1);

use App\Framework\Database\QueryOptimization\QueryLogger;

describe('QueryLogger', function () {
    beforeEach(function () {
        $this->logger = new QueryLogger();
    });

    it('starts disabled by default', function () {
        expect($this->logger->isEnabled())->toBeFalse();
    });

    it('enables and disables logging', function () {
        $this->logger->enable();
        expect($this->logger->isEnabled())->toBeTrue();

        $this->logger->disable();
        expect($this->logger->isEnabled())->toBeFalse();
    });

    it('ignores queries when disabled', function () {
        $this->logger->disable();

        $this->logger->logQuery('SELECT * FROM users', [], 5.0);

        expect($this->logger->getQueryCount())->toBe(0);
    });

    it('logs queries when enabled', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users WHERE id = ?', [1], 5.5, 1);

        expect($this->logger->getQueryCount())->toBe(1);

        $logs = $this->logger->getQueryLogs();
        expect($logs)->toHaveCount(1);
        expect($logs[0]->sql)->toBe('SELECT * FROM users WHERE id = ?');
        expect($logs[0]->bindings)->toBe([1]);
        expect($logs[0]->executionTimeMs)->toBe(5.5);
        expect($logs[0]->rowCount)->toBe(1);
    });

    it('captures stack trace', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 5.0);

        $logs = $this->logger->getQueryLogs();
        expect($logs[0]->stackTrace)->not->toBeEmpty();
    });

    it('identifies caller class and method', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 5.0);

        $logs = $this->logger->getQueryLogs();
        expect($logs[0]->callerClass)->not->toBeNull();
        expect($logs[0]->callerMethod)->not->toBeNull();
    });

    it('calculates total execution time', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 5.0);
        $this->logger->logQuery('SELECT * FROM posts', [], 10.0);
        $this->logger->logQuery('SELECT * FROM comments', [], 3.5);

        expect($this->logger->getTotalExecutionTime())->toBe(18.5);
    });

    it('groups queries by pattern', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users WHERE id = ?', [1], 5.0);
        $this->logger->logQuery('SELECT * FROM users WHERE id = ?', [2], 4.5);
        $this->logger->logQuery('SELECT * FROM posts WHERE user_id = ?', [1], 3.0);

        $grouped = $this->logger->getGroupedByPattern();

        expect($grouped)->toHaveCount(2);
        expect($grouped['SELECT * FROM users WHERE id = ?'])->toHaveCount(2);
        expect($grouped['SELECT * FROM posts WHERE user_id = ?'])->toHaveCount(1);
    });

    it('identifies slow queries', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 50.0);
        $this->logger->logQuery('SELECT * FROM posts', [], 150.0);
        $this->logger->logQuery('SELECT * FROM comments', [], 5.0);

        $slowQueries = $this->logger->getSlowQueries(100.0);

        expect($slowQueries)->toHaveCount(1);
        expect($slowQueries[0]->sql)->toContain('posts');
        expect($slowQueries[0]->executionTimeMs)->toBe(150.0);
    });

    it('clears logged queries', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 5.0);
        $this->logger->logQuery('SELECT * FROM posts', [], 3.0);

        expect($this->logger->getQueryCount())->toBe(2);

        $this->logger->clear();

        expect($this->logger->getQueryCount())->toBe(0);
        expect($this->logger->getQueryLogs())->toBeEmpty();
    });

    it('generates query statistics', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 5.0);
        $this->logger->logQuery('SELECT * FROM posts', [], 10.0);
        $this->logger->logQuery('INSERT INTO logs (message) VALUES (?)', ['test'], 2.0);
        $this->logger->logQuery('UPDATE users SET name = ? WHERE id = ?', ['John', 1], 3.0);
        $this->logger->logQuery('DELETE FROM logs WHERE id = ?', [1], 1.5);
        $this->logger->logQuery('SELECT * FROM users', [], 150.0); // Slow query

        $stats = $this->logger->getStatistics();

        expect($stats['total_queries'])->toBe(6);
        expect($stats['total_time_ms'])->toBe(171.5);
        expect($stats['select_count'])->toBe(3);
        expect($stats['insert_count'])->toBe(1);
        expect($stats['update_count'])->toBe(1);
        expect($stats['delete_count'])->toBe(1);
        expect($stats['slow_queries'])->toBe(1);
        expect($stats['unique_patterns'])->toBe(5);
    });

    it('calculates average execution time', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 10.0);
        $this->logger->logQuery('SELECT * FROM posts', [], 20.0);
        $this->logger->logQuery('SELECT * FROM comments', [], 30.0);

        $stats = $this->logger->getStatistics();

        expect($stats['average_time_ms'])->toBe(20.0);
    });

    it('handles empty query logs in statistics', function () {
        $this->logger->enable();

        $stats = $this->logger->getStatistics();

        expect($stats['total_queries'])->toBe(0);
        expect($stats['average_time_ms'])->toBe(0.0);
    });

    it('skips framework internals when finding caller', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 5.0);

        $logs = $this->logger->getQueryLogs();

        // Caller should not be from /Framework/Database/ or /vendor/
        if ($logs[0]->callerClass) {
            expect($logs[0]->callerClass)->not->toContain('Framework\\Database');
            expect($logs[0]->callerClass)->not->toContain('vendor');
        }
    });

    it('formats stack trace correctly', function () {
        $this->logger->enable();

        $this->logger->logQuery('SELECT * FROM users', [], 5.0);

        $logs = $this->logger->getQueryLogs();
        $stackTrace = $logs[0]->stackTrace;

        // Stack trace should contain class/method and file:line format
        expect($stackTrace)->toMatch('/.+\(.+:\d+\)/');
    });
});
