<?php

declare(strict_types=1);

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

describe('QueryLog Value Object', function () {
    it('creates query log with all properties', function () {
        $log = new QueryLog(
            sql: 'SELECT * FROM users WHERE id = ?',
            bindings: [123],
            executionTimeMs: 5.5,
            stackTrace: 'UserController::index',
            rowCount: 1,
            callerClass: 'UserController',
            callerMethod: 'index',
            callerLine: 42
        );

        expect($log->sql)->toBe('SELECT * FROM users WHERE id = ?');
        expect($log->bindings)->toBe([123]);
        expect($log->executionTimeMs)->toBe(5.5);
        expect($log->rowCount)->toBe(1);
        expect($log->callerClass)->toBe('UserController');
        expect($log->callerMethod)->toBe('index');
        expect($log->callerLine)->toBe(42);
    });

    it('normalizes SQL pattern correctly', function () {
        $log = new QueryLog(
            sql: "SELECT * FROM users WHERE id = 123 AND email = 'test@example.com'",
            bindings: [],
            executionTimeMs: 1.0,
            stackTrace: ''
        );

        $pattern = $log->getPattern();

        expect($pattern)->toBe('SELECT * FROM users WHERE id = ? AND email = ?');
    });

    it('normalizes IN clauses', function () {
        $log = new QueryLog(
            sql: 'SELECT * FROM users WHERE id IN (1, 2, 3, 4, 5)',
            bindings: [],
            executionTimeMs: 1.0,
            stackTrace: ''
        );

        $pattern = $log->getPattern();

        expect($pattern)->toBe('SELECT * FROM users WHERE id IN (?)');
    });

    it('detects SELECT queries', function () {
        $log = new QueryLog(
            sql: 'SELECT * FROM users',
            bindings: [],
            executionTimeMs: 1.0,
            stackTrace: ''
        );

        expect($log->isSelect())->toBeTrue();
        expect($log->isInsert())->toBeFalse();
        expect($log->isUpdate())->toBeFalse();
        expect($log->isDelete())->toBeFalse();
    });

    it('detects INSERT queries', function () {
        $log = new QueryLog(
            sql: 'INSERT INTO users (name, email) VALUES (?, ?)',
            bindings: ['John', 'john@example.com'],
            executionTimeMs: 2.0,
            stackTrace: ''
        );

        expect($log->isInsert())->toBeTrue();
        expect($log->isSelect())->toBeFalse();
    });

    it('extracts table name from SELECT', function () {
        $log = new QueryLog(
            sql: 'SELECT * FROM users WHERE id = ?',
            bindings: [1],
            executionTimeMs: 1.0,
            stackTrace: ''
        );

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

    it('extracts table name from INSERT', function () {
        $log = new QueryLog(
            sql: 'INSERT INTO orders (user_id, total) VALUES (?, ?)',
            bindings: [1, 100],
            executionTimeMs: 1.0,
            stackTrace: ''
        );

        expect($log->getTableName())->toBe('orders');
    });

    it('detects WHERE clause', function () {
        $log = new QueryLog(
            sql: 'SELECT * FROM users WHERE id = ?',
            bindings: [1],
            executionTimeMs: 1.0,
            stackTrace: ''
        );

        expect($log->hasWhereClause())->toBeTrue();
    });

    it('detects missing WHERE clause', function () {
        $log = new QueryLog(
            sql: 'SELECT * FROM users',
            bindings: [],
            executionTimeMs: 1.0,
            stackTrace: ''
        );

        expect($log->hasWhereClause())->toBeFalse();
    });

    it('detects JOIN queries', function () {
        $log = new QueryLog(
            sql: 'SELECT * FROM users LEFT JOIN profiles ON users.id = profiles.user_id',
            bindings: [],
            executionTimeMs: 1.0,
            stackTrace: ''
        );

        expect($log->hasJoin())->toBeTrue();
    });

    it('detects slow queries', function () {
        $log = new QueryLog(
            sql: 'SELECT * FROM users',
            bindings: [],
            executionTimeMs: 150.0,
            stackTrace: ''
        );

        expect($log->isSlow(100.0))->toBeTrue();
        expect($log->isSlow(200.0))->toBeFalse();
    });

    it('throws on negative execution time', function () {
        new QueryLog(
            sql: 'SELECT * FROM users',
            bindings: [],
            executionTimeMs: -5.0,
            stackTrace: ''
        );
    })->throws(InvalidArgumentException::class, 'Execution time cannot be negative');

    it('throws on negative row count', function () {
        new QueryLog(
            sql: 'SELECT * FROM users',
            bindings: [],
            executionTimeMs: 1.0,
            stackTrace: '',
            rowCount: -1
        );
    })->throws(InvalidArgumentException::class, 'Row count cannot be negative');
});
