<?php

declare(strict_types=1);

use App\Framework\Logging\LogLevel;
use App\Framework\Logging\LogRecord;
use App\Framework\Logging\Processors\IntrospectionProcessor;
use App\Framework\Logging\ValueObjects\LogContext;

describe('IntrospectionProcessor', function () {
    beforeEach(function () {
        $this->timestamp = new DateTimeImmutable('2024-01-15 10:30:45', new DateTimeZone('Europe/Berlin'));
    });

    describe('constructor', function () {
        it('can be instantiated with default config', function () {
            $processor = new IntrospectionProcessor();

            expect($processor instanceof IntrospectionProcessor)->toBeTrue();
        });

        it('can be instantiated with custom skip classes', function () {
            $processor = new IntrospectionProcessor(
                skipClassesPartials: ['Custom\\Namespace\\'],
                skipStackFrames: 3
            );

            expect($processor instanceof IntrospectionProcessor)->toBeTrue();
        });
    });

    describe('getPriority()', function () {
        it('returns priority 7', function () {
            $processor = new IntrospectionProcessor();

            expect($processor->getPriority())->toBe(7);
        });
    });

    describe('getName()', function () {
        it('returns name introspection', function () {
            $processor = new IntrospectionProcessor();

            expect($processor->getName())->toBe('introspection');
        });
    });

    describe('processRecord()', function () {
        it('adds introspection data with file and line', function () {
            $processor = new IntrospectionProcessor();

            $record = new LogRecord(
                message: 'Test message',
                context: LogContext::empty(),
                level: LogLevel::INFO,
                timestamp: $this->timestamp
            );

            $processed = $processor->processRecord($record);

            $introspection = $processed->getExtra('introspection');

            expect($introspection)->toBeArray();
            expect(isset($introspection['file']))->toBeTrue();
            expect(isset($introspection['line']))->toBeTrue();
            expect(isset($introspection['class']))->toBeTrue();
            expect(isset($introspection['function']))->toBeTrue();
        });

        it('includes test file information', function () {
            $processor = new IntrospectionProcessor();

            $record = new LogRecord(
                message: 'Test',
                context: LogContext::empty(),
                level: LogLevel::INFO,
                timestamp: $this->timestamp
            );

            $processed = $processor->processRecord($record);

            $introspection = $processed->getExtra('introspection');

            expect($introspection['file'])->toBeString();
            expect($introspection['line'])->toBeInt();
            expect($introspection['line'])->toBeGreaterThan(0);
            // Verify file path is not empty
            expect(strlen($introspection['file']) > 0)->toBeTrue();
        });

        it('skips logger infrastructure classes by default', function () {
            $processor = new IntrospectionProcessor();

            $record = new LogRecord(
                message: 'Test',
                context: LogContext::empty(),
                level: LogLevel::INFO,
                timestamp: $this->timestamp
            );

            $processed = $processor->processRecord($record);

            $introspection = $processed->getExtra('introspection');

            // Should not include logging infrastructure classes
            // (In test context, class may be empty or contain Pest/PHPUnit classes)
            expect($introspection['class'])->toBeString();
        });

        it('respects custom skip classes configuration', function () {
            $processor = new IntrospectionProcessor(
                skipClassesPartials: ['Pest\\', 'PHPUnit\\']
            );

            $record = new LogRecord(
                message: 'Test',
                context: LogContext::empty(),
                level: LogLevel::INFO,
                timestamp: $this->timestamp
            );

            $processed = $processor->processRecord($record);

            $introspection = $processed->getExtra('introspection');

            expect($introspection)->toBeArray();
            expect(isset($introspection['file']))->toBeTrue();
        });

        it('handles empty skip classes list', function () {
            $processor = new IntrospectionProcessor(
                skipClassesPartials: []
            );

            $record = new LogRecord(
                message: 'Test',
                context: LogContext::empty(),
                level: LogLevel::INFO,
                timestamp: $this->timestamp
            );

            $processed = $processor->processRecord($record);

            $introspection = $processed->getExtra('introspection');

            expect($introspection)->toBeArray();
            expect(isset($introspection['file']))->toBeTrue();
        });

        it('includes class and function information', function () {
            $processor = new IntrospectionProcessor();

            $record = new LogRecord(
                message: 'Test',
                context: LogContext::empty(),
                level: LogLevel::INFO,
                timestamp: $this->timestamp
            );

            $processed = $processor->processRecord($record);

            $introspection = $processed->getExtra('introspection');

            // In test context, these will be Pest/PHPUnit functions
            expect($introspection['class'])->toBeString();
            expect($introspection['function'])->toBeString();
        });
    });

    describe('readonly behavior', function () {
        it('is a final class', function () {
            $reflection = new ReflectionClass(IntrospectionProcessor::class);

            expect($reflection->isFinal())->toBeTrue();
        });
    });
});
