<?php

declare(strict_types=1);

use App\Framework\Database\QueryOptimization\Analysis\EagerLoadingAnalyzer;
use App\Framework\Database\QueryOptimization\Analysis\NPlusOneDetector;
use App\Framework\Database\QueryOptimization\NPlusOneDetectionService;
use App\Framework\Database\QueryOptimization\QueryLogger;
use App\Framework\Database\QueryOptimization\ValueObjects\QueryLog;
use App\Framework\Logging\Logger;

describe('NPlusOneDetectionService', function () {
    beforeEach(function () {
        $this->queryLogger = new QueryLogger();
        $this->detector = new NPlusOneDetector();
        $this->analyzer = new EagerLoadingAnalyzer();
        $this->logger = $this->createMock(Logger::class);

        $this->service = new NPlusOneDetectionService(
            $this->queryLogger,
            $this->detector,
            $this->analyzer,
            $this->logger
        );
    });

    it('starts and stops logging', function () {
        expect($this->queryLogger->isEnabled())->toBeFalse();

        $this->service->startLogging();
        expect($this->queryLogger->isEnabled())->toBeTrue();

        $this->service->stopLogging();
        expect($this->queryLogger->isEnabled())->toBeFalse();
    });

    it('analyzes logged queries', function () {
        // Enable logging
        $this->service->startLogging();

        // Simulate N+1 queries
        for ($i = 1; $i <= 10; $i++) {
            $this->queryLogger->logQuery(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 5.0,
                rowCount: 1
            );
        }

        // Analyze
        $result = $this->service->analyze();

        expect($result)->toHaveKeys(['detections', 'strategies', 'statistics']);
        expect($result['detections'])->not->toBeEmpty();
        expect($result['statistics']['total_queries'])->toBe(10);
    });

    it('generates formatted report', function () {
        $this->service->startLogging();

        // Simulate N+1 queries
        for ($i = 1; $i <= 10; $i++) {
            $this->queryLogger->logQuery(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 5.0,
                rowCount: 1
            );
        }

        $report = $this->service->analyzeAndReport();

        expect($report)->toContain('N+1 Query Detection Report');
        expect($report)->toContain('Query Statistics');
        expect($report)->toContain('N+1 Problems Detected');
    });

    it('profiles code execution', function () {
        $executedCallable = false;

        $analysis = $this->service->profile(function () use (&$executedCallable) {
            $executedCallable = true;
            return 'result';
        });

        expect($executedCallable)->toBeTrue();
        expect($analysis)->toHaveKey('execution_time_ms');
        expect($analysis)->toHaveKey('callback_result');
        expect($analysis['callback_result'])->toBe('result');
    });

    it('returns critical problems only', function () {
        $this->service->startLogging();

        // Add critical N+1 (high execution count)
        for ($i = 1; $i <= 50; $i++) {
            $this->queryLogger->logQuery(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 10.0,
                rowCount: 1
            );
        }

        // Add low severity N+1
        for ($i = 1; $i <= 6; $i++) {
            $this->queryLogger->logQuery(
                sql: 'SELECT * FROM comments WHERE post_id = ?',
                bindings: [$i],
                executionTimeMs: 1.0,
                rowCount: 1
            );
        }

        $critical = $this->service->getCriticalProblems();

        // Should only contain the high-severity posts pattern
        expect($critical)->toHaveCount(1);
        expect($critical[0]->isCritical())->toBeTrue();
    });

    it('quick check detects N+1 problems', function () {
        $this->service->startLogging();

        for ($i = 1; $i <= 10; $i++) {
            $this->queryLogger->logQuery(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 5.0,
                rowCount: 1
            );
        }

        expect($this->service->hasNPlusOneProblems())->toBeTrue();
    });

    it('returns query statistics', function () {
        $this->service->startLogging();

        $this->queryLogger->logQuery('SELECT * FROM users', [], 5.0, 10);
        $this->queryLogger->logQuery('INSERT INTO logs (message) VALUES (?)', ['test'], 2.0, 1);
        $this->queryLogger->logQuery('UPDATE users SET name = ? WHERE id = ?', ['John', 1], 3.0, 1);

        $stats = $this->service->getQueryStatistics();

        expect($stats['total_queries'])->toBe(3);
        expect($stats['select_count'])->toBe(1);
        expect($stats['insert_count'])->toBe(1);
        expect($stats['update_count'])->toBe(1);
    });

    it('clears query logs', function () {
        $this->service->startLogging();

        $this->queryLogger->logQuery('SELECT * FROM users', [], 5.0);
        expect($this->service->getQueryLogs())->toHaveCount(1);

        $this->service->clearLogs();
        expect($this->service->getQueryLogs())->toBeEmpty();
    });

    it('integrates detections with eager loading strategies', function () {
        $this->service->startLogging();

        // Create N+1 pattern
        for ($i = 1; $i <= 15; $i++) {
            $this->queryLogger->logQuery(
                sql: 'SELECT * FROM posts WHERE user_id = ?',
                bindings: [$i],
                executionTimeMs: 8.0,
                rowCount: 1
            );
        }

        $result = $this->service->analyze();

        expect($result['detections'])->toHaveCount(1);
        expect($result['strategies'])->toHaveCount(1);

        $strategy = $result['strategies'][0];
        expect($strategy->tableName)->toBe('posts');
        expect($strategy->codeExample)->toContain('eager loading');
    });

    it('handles empty query logs gracefully', function () {
        $this->service->startLogging();

        $result = $this->service->analyze();

        expect($result['detections'])->toBeEmpty();
        expect($result['strategies'])->toBeEmpty();
        expect($result['statistics']['total_queries'])->toBe(0);
    });

    it('logs analysis completion', function () {
        $this->logger->expects($this->once())
            ->method('info')
            ->with(
                $this->stringContains('Analysis completed'),
                $this->anything()
            );

        $this->service->startLogging();
        $this->queryLogger->logQuery('SELECT * FROM users', [], 5.0);
        $this->service->analyze();
    });
});
