<?php

declare(strict_types=1);

use Illuminate\Support\Facades\File;

function tempAppPath(): string
{
    return sys_get_temp_dir().'/builder-make-test-'.uniqid('', true);
}

function cleanupDir(string $path): void
{
    if (is_dir($path)) {
        File::deleteDirectory($path);
    }
}

// ─────────────────────────────────────────────
// builder:make:resource
// ─────────────────────────────────────────────

describe('builder:make:resource', function (): void {
    beforeEach(function (): void {
        $this->tmpPath = tempAppPath();
        $this->app->useAppPath($this->tmpPath);
    });

    afterEach(function (): void {
        cleanupDir($this->tmpPath);
    });

    it('generates the resource file at the correct path', function (): void {
        $this->artisan('builder:make:resource', ['name' => 'PostResource'])
            ->assertSuccessful();

        expect(file_exists($this->tmpPath.'/Builder/Resources/PostResource.php'))->toBeTrue();
    });

    it('replaces all placeholders correctly', function (): void {
        $this->artisan('builder:make:resource', ['name' => 'PostResource'])
            ->assertSuccessful();

        $content = (string) file_get_contents($this->tmpPath.'/Builder/Resources/PostResource.php');

        expect($content)
            ->toContain('namespace App\\Builder\\Resources;')
            ->toContain('class PostResource extends Resource')
            ->toContain("return 'posts';")
            ->toContain("return 'Posts';")
            ->toContain("return 'Post';")
            ->toContain('\App\Models\Post::class');
    });

    it('uses --model option when provided', function (): void {
        $this->artisan('builder:make:resource', ['name' => 'PostResource', '--model' => 'Article'])
            ->assertSuccessful();

        $content = (string) file_get_contents($this->tmpPath.'/Builder/Resources/PostResource.php');

        expect($content)->toContain('\App\Models\Article::class');
    });

    it('derives kebab plural slug from class name', function (): void {
        $this->artisan('builder:make:resource', ['name' => 'BlogPostResource'])
            ->assertSuccessful();

        $content = (string) file_get_contents($this->tmpPath.'/Builder/Resources/BlogPostResource.php');

        expect($content)->toContain("return 'blog-posts';");
    });

    it('fails if file already exists without --force', function (): void {
        $this->artisan('builder:make:resource', ['name' => 'PostResource'])->assertSuccessful();

        $this->artisan('builder:make:resource', ['name' => 'PostResource'])->assertFailed();
    });

    it('overwrites an existing file with --force', function (): void {
        $this->artisan('builder:make:resource', ['name' => 'PostResource'])->assertSuccessful();

        $this->artisan('builder:make:resource', ['name' => 'PostResource', '--force' => true])
            ->assertSuccessful();

        expect(file_exists($this->tmpPath.'/Builder/Resources/PostResource.php'))->toBeTrue();
    });

    it('uses published stub when present', function (): void {
        $publishedDir = base_path('stubs/builder');
        @mkdir($publishedDir, 0755, true);
        file_put_contents($publishedDir.'/resource.stub', '<?php // custom stub for {{ class }}');

        $this->artisan('builder:make:resource', ['name' => 'PostResource'])->assertSuccessful();

        $content = (string) file_get_contents($this->tmpPath.'/Builder/Resources/PostResource.php');

        expect($content)->toContain('// custom stub for PostResource');

        unlink($publishedDir.'/resource.stub');
        @rmdir($publishedDir);
    });
});

// ─────────────────────────────────────────────
// builder:make:widget
// ─────────────────────────────────────────────

describe('builder:make:widget', function (): void {
    beforeEach(function (): void {
        $this->tmpPath = tempAppPath();
        $this->app->useAppPath($this->tmpPath);
    });

    afterEach(function (): void {
        cleanupDir($this->tmpPath);
    });

    it('generates the widget file at the correct path', function (): void {
        $this->artisan('builder:make:widget', ['name' => 'PostStatsWidget'])
            ->assertSuccessful();

        expect(file_exists($this->tmpPath.'/Builder/Widgets/PostStatsWidget.php'))->toBeTrue();
    });

    it('replaces all placeholders correctly', function (): void {
        $this->artisan('builder:make:widget', ['name' => 'PostStatsWidget'])
            ->assertSuccessful();

        $content = (string) file_get_contents($this->tmpPath.'/Builder/Widgets/PostStatsWidget.php');

        expect($content)
            ->toContain('namespace App\\Builder\\Widgets;')
            ->toContain('class PostStatsWidget extends Widget')
            ->toContain("return 'post-stats';")
            ->toContain("return 'Post Stats';")
            ->toContain("return 'PostStatsWidget';");
    });

    it('fails if file already exists without --force', function (): void {
        $this->artisan('builder:make:widget', ['name' => 'PostStatsWidget'])->assertSuccessful();

        $this->artisan('builder:make:widget', ['name' => 'PostStatsWidget'])->assertFailed();
    });

    it('overwrites an existing file with --force', function (): void {
        $this->artisan('builder:make:widget', ['name' => 'PostStatsWidget'])->assertSuccessful();

        $this->artisan('builder:make:widget', ['name' => 'PostStatsWidget', '--force' => true])
            ->assertSuccessful();

        expect(file_exists($this->tmpPath.'/Builder/Widgets/PostStatsWidget.php'))->toBeTrue();
    });
});

// ─────────────────────────────────────────────
// builder:make:settings
// ─────────────────────────────────────────────

describe('builder:make:settings', function (): void {
    beforeEach(function (): void {
        $this->tmpPath = tempAppPath();
        $this->app->useAppPath($this->tmpPath);
    });

    afterEach(function (): void {
        cleanupDir($this->tmpPath);
    });

    it('generates the settings file at the correct path', function (): void {
        $this->artisan('builder:make:settings', ['name' => 'SkeletonSettings'])
            ->assertSuccessful();

        expect(file_exists($this->tmpPath.'/Builder/Settings/SkeletonSettings.php'))->toBeTrue();
    });

    it('replaces all placeholders correctly', function (): void {
        $this->artisan('builder:make:settings', ['name' => 'SkeletonSettings'])
            ->assertSuccessful();

        $content = (string) file_get_contents($this->tmpPath.'/Builder/Settings/SkeletonSettings.php');

        expect($content)
            ->toContain('namespace App\\Builder\\Settings;')
            ->toContain('class SkeletonSettings extends BuilderSettings')
            ->toContain("return 'skeleton';")
            ->toContain("return 'Skeleton';");
    });

    it('derives snake_case group from multi-word class name', function (): void {
        $this->artisan('builder:make:settings', ['name' => 'SiteGeneralSettings'])
            ->assertSuccessful();

        $content = (string) file_get_contents($this->tmpPath.'/Builder/Settings/SiteGeneralSettings.php');

        expect($content)->toContain("return 'site_general';");
    });

    it('fails if file already exists without --force', function (): void {
        $this->artisan('builder:make:settings', ['name' => 'SkeletonSettings'])->assertSuccessful();

        $this->artisan('builder:make:settings', ['name' => 'SkeletonSettings'])->assertFailed();
    });

    it('overwrites an existing file with --force', function (): void {
        $this->artisan('builder:make:settings', ['name' => 'SkeletonSettings'])->assertSuccessful();

        $this->artisan('builder:make:settings', ['name' => 'SkeletonSettings', '--force' => true])
            ->assertSuccessful();

        expect(file_exists($this->tmpPath.'/Builder/Settings/SkeletonSettings.php'))->toBeTrue();
    });
});
