<?php

declare(strict_types=1);

use App\Framework\OutputBuffer\CapturedOutput;

describe('CapturedOutput', function () {
    it('stores content and result', function () {
        $captured = new CapturedOutput(
            content: "test output",
            result: 42,
            level: 1
        );

        expect($captured->content)->toBe("test output");
        expect($captured->result)->toBe(42);
        expect($captured->level)->toBe(1);
    });

    describe('isEmpty()', function () {
        it('returns true for empty content', function () {
            $captured = new CapturedOutput("", null, 1);
            expect($captured->isEmpty())->toBeTrue();
        });

        it('returns true for whitespace-only content', function () {
            $captured = new CapturedOutput("   \n\t  ", null, 1);
            expect($captured->isEmpty())->toBeTrue();
        });

        it('returns false for non-empty content', function () {
            $captured = new CapturedOutput("test", null, 1);
            expect($captured->isEmpty())->toBeFalse();
        });
    });

    describe('hasContent()', function () {
        it('returns false for empty content', function () {
            $captured = new CapturedOutput("", null, 1);
            expect($captured->hasContent())->toBeFalse();
        });

        it('returns true for non-empty content', function () {
            $captured = new CapturedOutput("test", null, 1);
            expect($captured->hasContent())->toBeTrue();
        });
    });

    describe('lines()', function () {
        it('returns empty array for empty content', function () {
            $captured = new CapturedOutput("", null, 1);
            expect($captured->lines())->toBe([]);
        });

        it('splits content into lines', function () {
            $captured = new CapturedOutput("Line 1\nLine 2\nLine 3", null, 1);
            expect($captured->lines())->toBe(['Line 1', 'Line 2', 'Line 3']);
        });

        it('filters empty lines', function () {
            $captured = new CapturedOutput("Line 1\n\nLine 2\n\n", null, 1);
            expect($captured->lines())->toBe(['Line 1', 'Line 2']);
        });

        it('trims whitespace from lines', function () {
            $captured = new CapturedOutput("  Line 1  \n  Line 2  ", null, 1);
            expect($captured->lines())->toBe(['Line 1', 'Line 2']);
        });
    });

    describe('lineCount()', function () {
        it('returns 0 for empty content', function () {
            $captured = new CapturedOutput("", null, 1);
            expect($captured->lineCount())->toBe(0);
        });

        it('returns correct line count', function () {
            $captured = new CapturedOutput("Line 1\nLine 2\nLine 3", null, 1);
            expect($captured->lineCount())->toBe(3);
        });

        it('excludes empty lines from count', function () {
            $captured = new CapturedOutput("Line 1\n\n\nLine 2", null, 1);
            expect($captured->lineCount())->toBe(2);
        });
    });

    describe('length()', function () {
        it('returns 0 for empty content', function () {
            $captured = new CapturedOutput("", null, 1);
            expect($captured->length())->toBe(0);
        });

        it('returns byte length of content', function () {
            $captured = new CapturedOutput("test", null, 1);
            expect($captured->length())->toBe(4);
        });

        it('counts multibyte characters correctly', function () {
            $captured = new CapturedOutput("café", null, 1);
            expect($captured->length())->toBe(5); // UTF-8 encoding
        });
    });

    describe('contains()', function () {
        it('returns false for empty content', function () {
            $captured = new CapturedOutput("", null, 1);
            expect($captured->contains("test"))->toBeFalse();
        });

        it('returns true when content contains string', function () {
            $captured = new CapturedOutput("Hello World", null, 1);
            expect($captured->contains("World"))->toBeTrue();
        });

        it('returns false when content does not contain string', function () {
            $captured = new CapturedOutput("Hello World", null, 1);
            expect($captured->contains("Goodbye"))->toBeFalse();
        });

        it('is case-sensitive', function () {
            $captured = new CapturedOutput("Hello World", null, 1);
            expect($captured->contains("world"))->toBeFalse();
        });
    });

    describe('trimmed()', function () {
        it('returns empty string for empty content', function () {
            $captured = new CapturedOutput("", null, 1);
            expect($captured->trimmed())->toBe("");
        });

        it('trims whitespace from content', function () {
            $captured = new CapturedOutput("  test  \n", null, 1);
            expect($captured->trimmed())->toBe("test");
        });

        it('does not modify original content', function () {
            $captured = new CapturedOutput("  test  ", null, 1);
            $trimmed = $captured->trimmed();

            expect($captured->content)->toBe("  test  ");
            expect($trimmed)->toBe("test");
        });
    });

    describe('result handling', function () {
        it('stores null result', function () {
            $captured = new CapturedOutput("test", null, 1);
            expect($captured->result)->toBeNull();
        });

        it('stores scalar result', function () {
            $captured = new CapturedOutput("test", 42, 1);
            expect($captured->result)->toBe(42);
        });

        it('stores array result', function () {
            $captured = new CapturedOutput("test", ['a' => 1], 1);
            expect($captured->result)->toBe(['a' => 1]);
        });

        it('stores object result', function () {
            $obj = new stdClass();
            $captured = new CapturedOutput("test", $obj, 1);
            expect($captured->result)->toBe($obj);
        });
    });
});
