<?php

declare(strict_types=1);

use App\Framework\Filesystem\ValueObjects\FilePath;
use App\Framework\Filesystem\TemporaryDirectory;
use App\Framework\Exception\FrameworkException;

describe('TemporaryDirectory', function () {
    it('creates temporary directory with default name', function () {
        $temp = TemporaryDirectory::make()->create();

        expect($temp->exists())->toBeTrue();
        expect($temp->getPath()->isDirectory())->toBeTrue();

        // Cleanup
        $temp->delete();
    });

    it('creates temporary directory with custom name', function () {
        $temp = TemporaryDirectory::make()
            ->name('my-custom-temp')
            ->create();

        $path = $temp->getPath();

        expect($path->getFilename())->toBe('my-custom-temp');
        expect($temp->exists())->toBeTrue();

        $temp->delete();
    });

    it('creates temporary directory in custom location', function () {
        $customLocation = FilePath::tempDir()->join('custom-temp-location');

        if (!$customLocation->isDirectory()) {
            mkdir($customLocation->toString(), 0755, true);
        }

        $temp = TemporaryDirectory::make()
            ->location($customLocation)
            ->name('nested-temp')
            ->create();

        expect($temp->exists())->toBeTrue();
        expect($temp->getPath()->toString())->toContain('custom-temp-location');

        $temp->delete();
        rmdir($customLocation->toString());
    });

    it('sanitizes directory names', function () {
        $temp = TemporaryDirectory::make()
            ->name('my/dangerous\\name:with*symbols')
            ->create();

        $filename = $temp->getPath()->getFilename();

        expect($filename)->not->toContain('/');
        expect($filename)->not->toContain('\\');
        expect($filename)->not->toContain(':');
        expect($filename)->not->toContain('*');

        $temp->delete();
    });

    it('throws exception when directory exists without force', function () {
        $temp = TemporaryDirectory::make()
            ->name('existing-dir')
            ->create();

        expect(fn () => TemporaryDirectory::make()
            ->name('existing-dir')
            ->create()
        )->toThrow(FrameworkException::class);

        $temp->delete();
    });

    it('overwrites existing directory with force', function () {
        $temp1 = TemporaryDirectory::make()
            ->name('overwrite-test')
            ->create();

        // Create a file in the first directory
        $testFile = $temp1->path('test.txt');
        file_put_contents($testFile->toString(), 'test content');

        $temp2 = TemporaryDirectory::make()
            ->name('overwrite-test')
            ->force()
            ->create();

        // File should be gone
        expect($testFile->exists())->toBeFalse();
        expect($temp2->exists())->toBeTrue();

        $temp2->delete();
    });

    it('returns FilePath for files in directory', function () {
        $temp = TemporaryDirectory::make()->create();

        $filePath = $temp->path('subdir/file.txt');

        expect($filePath)->toBeInstanceOf(FilePath::class);
        expect($filePath->toString())->toContain('subdir');
        expect($filePath->toString())->toContain('file.txt');

        $temp->delete();
    });

    it('empties directory without deleting it', function () {
        $temp = TemporaryDirectory::make()->create();

        // Create some files
        file_put_contents($temp->path('file1.txt')->toString(), 'content1');
        file_put_contents($temp->path('file2.txt')->toString(), 'content2');
        mkdir($temp->path('subdir')->toString());
        file_put_contents($temp->path('subdir/file3.txt')->toString(), 'content3');

        $temp->empty();

        // Directory should still exist
        expect($temp->exists())->toBeTrue();

        // But should be empty
        $items = iterator_to_array(new \FilesystemIterator($temp->getPath()->toString()));
        expect($items)->toHaveCount(0);

        $temp->delete();
    });

    it('deletes directory and all contents', function () {
        $temp = TemporaryDirectory::make()->create();
        $path = $temp->getPath();

        // Create nested structure
        mkdir($temp->path('dir1')->toString());
        mkdir($temp->path('dir1/dir2')->toString());
        file_put_contents($temp->path('dir1/dir2/file.txt')->toString(), 'nested');

        $result = $temp->delete();

        expect($result)->toBeTrue();
        expect($path->exists())->toBeFalse();
    });

    it('auto-deletes on destruct by default', function () {
        $temp = TemporaryDirectory::make()->create();
        $path = $temp->getPath();

        expect($path->isDirectory())->toBeTrue();

        // Explicitly trigger destruct and cleanup
        $temp->delete();
        unset($temp);

        // Directory should be deleted
        expect($path->exists())->toBeFalse();
    });

    it('does not auto-delete when disabled', function () {
        $path = null;

        {
            $temp = TemporaryDirectory::make()
                ->doNotDeleteWhenDestruct()
                ->create();

            $path = $temp->getPath();
        } // $temp goes out of scope

        // Directory should still exist
        expect($path->isDirectory())->toBeTrue();

        // Manual cleanup
        rmdir($path->toString());
    });

    it('throws exception when accessing path before creation', function () {
        $temp = TemporaryDirectory::make();

        expect(fn () => $temp->path())->toThrow(FrameworkException::class);
    });

    it('handles special characters in filenames', function () {
        $temp = TemporaryDirectory::make()
            ->name('test with spaces and-dashes_underscores')
            ->create();

        $filename = $temp->getPath()->getFilename();

        // Underscores are preserved, spaces become dashes
        expect($filename)->toBe('test-with-spaces-and-dashes_underscores');

        $temp->delete();
    });

    it('can chain method calls fluently', function () {
        $temp = TemporaryDirectory::make()
            ->name('fluent-test')
            ->location(FilePath::tempDir())
            ->force()
            ->doNotDeleteWhenDestruct()
            ->create();

        expect($temp)->toBeInstanceOf(TemporaryDirectory::class);
        expect($temp->exists())->toBeTrue();

        $temp->delete();
    });

    it('deletes deeply nested structures', function () {
        $temp = TemporaryDirectory::make()->create();

        // Create deep nesting
        $deepPath = $temp->path('a/b/c/d/e/f/g');
        mkdir($deepPath->toString(), 0755, true);
        file_put_contents($deepPath->join('file.txt')->toString(), 'deep content');

        expect($deepPath->exists())->toBeTrue();

        $temp->delete();

        expect($temp->getPath()->exists())->toBeFalse();
    });

    it('returns false when deleting non-existent directory', function () {
        $temp = TemporaryDirectory::make()->name('never-created');

        $result = $temp->delete();

        expect($result)->toBeFalse();
    });

    it('empty() does nothing on non-existent directory', function () {
        $temp = TemporaryDirectory::make()->name('never-created');

        // Should not throw
        $result = $temp->empty();

        expect($result)->toBeInstanceOf(TemporaryDirectory::class);
    });
});
