<?php

declare(strict_types=1);

use App\Framework\Database\QueryOptimization\ValueObjects\QueryLog;
use App\Framework\Database\QueryOptimization\ValueObjects\QueryPattern;

describe('QueryPattern Value Object', function () {
    it('groups queries by pattern', function () {
        $queries = [
            new QueryLog('SELECT * FROM users WHERE id = ?', [1], 5.0, ''),
            new QueryLog('SELECT * FROM users WHERE id = ?', [2], 4.5, ''),
            new QueryLog('SELECT * FROM users WHERE id = ?', [3], 6.0, ''),
        ];

        $pattern = new QueryPattern('SELECT * FROM users WHERE id = ?', $queries);

        expect($pattern->getExecutionCount())->toBe(3);
        expect($pattern->getTotalExecutionTimeMs())->toBe(15.5);
        expect($pattern->getAverageExecutionTimeMs())->toBe(5.166666666666667);
    });

    it('detects potential N+1 pattern', function () {
        $queries = [];

        for ($i = 1; $i <= 10; $i++) {
            $queries[] = new QueryLog(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 5.0,
                stackTrace: 'UserController::show'
            );
        }

        $pattern = new QueryPattern('SELECT * FROM posts WHERE user_id = ?', $queries);

        expect($pattern->isPotentialNPlusOne())->toBeTrue();
    });

    it('rejects pattern with too few executions', function () {
        $queries = [
            new QueryLog('SELECT * FROM users WHERE id = ?', [1], 5.0, ''),
            new QueryLog('SELECT * FROM users WHERE id = ?', [2], 5.0, ''),
        ];

        $pattern = new QueryPattern('SELECT * FROM users WHERE id = ?', $queries);

        expect($pattern->isPotentialNPlusOne())->toBeFalse();
    });

    it('rejects pattern without WHERE clause', function () {
        $queries = [];

        for ($i = 1; $i <= 10; $i++) {
            $queries[] = new QueryLog(
                sql: 'SELECT * FROM users',
                bindings: [],
                executionTimeMs: 5.0,
                stackTrace: ''
            );
        }

        $pattern = new QueryPattern('SELECT * FROM users', $queries);

        expect($pattern->isPotentialNPlusOne())->toBeFalse();
    });

    it('rejects pattern with JOIN', function () {
        $queries = [];

        for ($i = 1; $i <= 10; $i++) {
            $queries[] = new QueryLog(
                sql: 'SELECT * FROM users LEFT JOIN posts ON users.id = posts.user_id WHERE users.id = ?',
                bindings: [$i],
                executionTimeMs: 5.0,
                stackTrace: ''
            );
        }

        $pattern = new QueryPattern(
            'SELECT * FROM users LEFT JOIN posts ON users.id = posts.user_id WHERE users.id = ?',
            $queries
        );

        expect($pattern->isPotentialNPlusOne())->toBeFalse();
    });

    it('calculates N+1 severity correctly', function () {
        $queries = [];

        // High execution count (20 queries)
        for ($i = 1; $i <= 20; $i++) {
            $queries[] = new QueryLog(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 10.0,
                stackTrace: 'UserController::show',
                callerClass: 'UserController',
                callerMethod: 'show'
            );
        }

        $pattern = new QueryPattern('SELECT * FROM posts WHERE user_id = ?', $queries);

        $severity = $pattern->getNPlusOneSeverity();

        // Should be high severity (execution count > 10, consistent caller, high total time)
        expect($severity)->toBeGreaterThan(6);
    });

    it('classifies severity levels correctly', function () {
        $highSeverityQueries = [];

        for ($i = 1; $i <= 50; $i++) {
            $highSeverityQueries[] = new QueryLog(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 15.0,
                stackTrace: 'UserController::show',
                callerClass: 'UserController',
                callerMethod: 'show'
            );
        }

        $pattern = new QueryPattern('SELECT * FROM posts WHERE user_id = ?', $highSeverityQueries);

        expect($pattern->getSeverityLevel())->toBeIn(['CRITICAL', 'HIGH']);
    });

    it('identifies table name', function () {
        $queries = [
            new QueryLog('SELECT * FROM users WHERE id = ?', [1], 5.0, ''),
        ];

        $pattern = new QueryPattern('SELECT * FROM users WHERE id = ?', $queries);

        expect($pattern->getTableName())->toBe('users');
    });

    it('checks for consistent caller', function () {
        $queries = [];

        for ($i = 1; $i <= 10; $i++) {
            $queries[] = new QueryLog(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 5.0,
                stackTrace: '',
                callerClass: 'UserController',
                callerMethod: 'show'
            );
        }

        $pattern = new QueryPattern('SELECT * FROM posts WHERE user_id = ?', $queries);

        expect($pattern->hasConsistentCaller())->toBeTrue();
    });

    it('detects inconsistent caller', function () {
        $queries = [
            new QueryLog('SELECT * FROM posts WHERE user_id = ?', [1], 5.0, '', callerClass: 'UserController', callerMethod: 'show'),
            new QueryLog('SELECT * FROM posts WHERE user_id = ?', [2], 5.0, '', callerClass: 'PostController', callerMethod: 'index'),
            new QueryLog('SELECT * FROM posts WHERE user_id = ?', [3], 5.0, '', callerClass: 'UserController', callerMethod: 'show'),
        ];

        $pattern = new QueryPattern('SELECT * FROM posts WHERE user_id = ?', $queries);

        expect($pattern->hasConsistentCaller())->toBeFalse();
    });

    it('gets caller locations', function () {
        $queries = [
            new QueryLog('SELECT * FROM posts WHERE user_id = ?', [1], 5.0, '', callerClass: 'UserController', callerMethod: 'show', callerLine: 42),
            new QueryLog('SELECT * FROM posts WHERE user_id = ?', [2], 5.0, '', callerClass: 'UserController', callerMethod: 'show', callerLine: 42),
        ];

        $pattern = new QueryPattern('SELECT * FROM posts WHERE user_id = ?', $queries);

        $locations = $pattern->getCallerLocations();

        expect($locations)->toContain('UserController::show:42');
    });
});
