<?php

declare(strict_types=1);

use App\Framework\OutputBuffer\OutputBufferFlag;
use App\Framework\OutputBuffer\OutputBufferFlags;

describe('OutputBufferFlags', function () {
    describe('variadic constructor', function () {
        it('accepts no flags', function () {
            $flags = new OutputBufferFlags();
            expect($flags->toBitmask())->toBe(0);
        });

        it('accepts single flag', function () {
            $flags = new OutputBufferFlags(OutputBufferFlag::CLEANABLE);
            expect($flags->has(OutputBufferFlag::CLEANABLE))->toBeTrue();
        });

        it('accepts multiple flags', function () {
            $flags = new OutputBufferFlags(
                OutputBufferFlag::CLEANABLE,
                OutputBufferFlag::FLUSHABLE
            );

            expect($flags->has(OutputBufferFlag::CLEANABLE))->toBeTrue();
            expect($flags->has(OutputBufferFlag::FLUSHABLE))->toBeTrue();
        });
    });

    describe('factory methods', function () {
        it('creates standard flags', function () {
            $flags = OutputBufferFlags::standard();
            expect($flags->has(OutputBufferFlag::STDFLAGS))->toBeTrue();
        });

        it('creates default flags', function () {
            $flags = OutputBufferFlags::default();
            expect($flags->has(OutputBufferFlag::CLEANABLE))->toBeTrue();
        });

        it('creates cleanable flags', function () {
            $flags = OutputBufferFlags::cleanable();
            expect($flags->has(OutputBufferFlag::CLEANABLE))->toBeTrue();
        });

        it('creates cleanable and flushable flags', function () {
            $flags = OutputBufferFlags::cleanableAndFlushable();
            expect($flags->has(OutputBufferFlag::CLEANABLE))->toBeTrue();
            expect($flags->has(OutputBufferFlag::FLUSHABLE))->toBeTrue();
        });
    });

    describe('toBitmask()', function () {
        it('returns 0 for no flags', function () {
            $flags = new OutputBufferFlags();
            expect($flags->toBitmask())->toBe(0);
        });

        it('returns correct value for single flag', function () {
            $flags = new OutputBufferFlags(OutputBufferFlag::CLEANABLE);
            expect($flags->toBitmask())->toBe(PHP_OUTPUT_HANDLER_CLEANABLE);
        });

        it('combines multiple flags with OR', function () {
            $flags = new OutputBufferFlags(
                OutputBufferFlag::CLEANABLE,
                OutputBufferFlag::FLUSHABLE
            );

            $expected = PHP_OUTPUT_HANDLER_CLEANABLE | PHP_OUTPUT_HANDLER_FLUSHABLE;
            expect($flags->toBitmask())->toBe($expected);
        });

        it('handles STDFLAGS correctly', function () {
            $flags = new OutputBufferFlags(OutputBufferFlag::STDFLAGS);
            expect($flags->toBitmask())->toBe(PHP_OUTPUT_HANDLER_STDFLAGS);
        });
    });

    describe('has()', function () {
        it('returns false when flag is not set', function () {
            $flags = new OutputBufferFlags(OutputBufferFlag::CLEANABLE);
            expect($flags->has(OutputBufferFlag::FLUSHABLE))->toBeFalse();
        });

        it('returns true when flag is set', function () {
            $flags = new OutputBufferFlags(OutputBufferFlag::CLEANABLE);
            expect($flags->has(OutputBufferFlag::CLEANABLE))->toBeTrue();
        });

        it('works with multiple flags', function () {
            $flags = new OutputBufferFlags(
                OutputBufferFlag::CLEANABLE,
                OutputBufferFlag::FLUSHABLE,
                OutputBufferFlag::REMOVABLE
            );

            expect($flags->has(OutputBufferFlag::CLEANABLE))->toBeTrue();
            expect($flags->has(OutputBufferFlag::FLUSHABLE))->toBeTrue();
            expect($flags->has(OutputBufferFlag::REMOVABLE))->toBeTrue();
        });
    });

    describe('toArray()', function () {
        it('returns empty array for no flags', function () {
            $flags = new OutputBufferFlags();
            expect($flags->toArray())->toBe([]);
        });

        it('returns all flags as array', function () {
            $flags = new OutputBufferFlags(
                OutputBufferFlag::CLEANABLE,
                OutputBufferFlag::FLUSHABLE
            );

            $array = $flags->toArray();
            expect($array)->toHaveCount(2);
            expect($array)->toContain(OutputBufferFlag::CLEANABLE);
            expect($array)->toContain(OutputBufferFlag::FLUSHABLE);
        });
    });
});
