<?php

namespace Mtc\Plugins\BlockManager\Tests\Feature;

use Illuminate\Support\Str;
use Mtc\Plugins\BlockManager\Models\BlockManagerBlock;
use Tests\TestCase;

class BlockCrudApiTest extends TestCase
{
    /** @var string[] */
    private array $createdUuids = [];

    protected function tearDown(): void
    {
        if (!empty($this->createdUuids)) {
            BlockManagerBlock::whereIn('uuid', $this->createdUuids)->delete();
        }
        parent::tearDown();
    }

    public function test_index_returns_data_envelope(): void
    {
        $response = $this->getJson('/api/block-manager');
        $response->assertStatus(200);
        $response->assertJsonStructure(['data']);
        $this->assertIsArray($response->json('data'));
    }

    public function test_index_lists_existing_blocks(): void
    {
        $a = $this->seedBlock('Phase3 A');
        $b = $this->seedBlock('Phase3 B');

        $data = $this->getJson('/api/block-manager')->json('data');
        $slugs = array_column($data, 'slug');

        $this->assertContains($a->slug, $slugs);
        $this->assertContains($b->slug, $slugs);
    }

    public function test_show_returns_block_payload(): void
    {
        $block = $this->seedBlock('Phase3 Show');

        $response = $this->getJson("/api/block-manager/{$block->id}");
        $response->assertStatus(200);
        $payload = $response->json('data');

        $this->assertSame($block->id, $payload['id']);
        $this->assertSame($block->slug, $payload['slug']);
        $this->assertSame('Phase3 Show', $payload['name']);
    }

    public function test_show_returns_404_for_unknown_id(): void
    {
        $this->getJson('/api/block-manager/99999999')->assertStatus(404);
    }

    public function test_store_creates_block_with_minimal_payload(): void
    {
        $name = 'Phase3 Minimal ' . Str::random(6);

        $response = $this->postJson('/api/block-manager', ['name' => $name]);
        $response->assertStatus(201);

        $payload = $response->json('data');
        $this->assertNotEmpty($payload['uuid']);
        $this->assertNotEmpty($payload['slug']);
        $this->assertSame($name, $payload['name']);
        $this->createdUuids[] = $payload['uuid'];

        $this->assertNotNull(BlockManagerBlock::where('uuid', $payload['uuid'])->first());
    }

    public function test_store_accepts_explicit_slug_and_structure(): void
    {
        $slug = 'phase3-explicit-' . Str::random(6);
        $structure = [
            'elements' => [
                ['instance_id' => 'el-001', 'element_type' => 'heading', 'variant' => 'default', 'field_name' => 'title'],
            ],
        ];

        $response = $this->postJson('/api/block-manager', [
            'name'           => 'Phase3 Explicit',
            'slug'           => $slug,
            'structure_json' => $structure,
        ]);
        $response->assertStatus(201);

        $payload = $response->json('data');
        $this->createdUuids[] = $payload['uuid'];

        $this->assertSame($slug, $payload['slug']);
        $this->assertSame('heading', $payload['structure_json']['elements'][0]['element_type']);

        $fresh = BlockManagerBlock::where('uuid', $payload['uuid'])->firstOrFail();
        $this->assertSame('heading', $fresh->structure_json['elements'][0]['element_type']);
    }

    public function test_store_validates_name_is_required(): void
    {
        $this->postJson('/api/block-manager', [])->assertStatus(422);
    }

    public function test_store_rejects_duplicate_slug(): void
    {
        $slug = 'phase3-dup-' . Str::random(6);

        $first = $this->postJson('/api/block-manager', ['name' => 'Phase3 Dup A', 'slug' => $slug]);
        $first->assertStatus(201);
        $this->createdUuids[] = $first->json('data.uuid');

        $second = $this->postJson('/api/block-manager', ['name' => 'Phase3 Dup B', 'slug' => $slug]);
        $second->assertStatus(422);
    }

    public function test_update_modifies_block(): void
    {
        $block = $this->seedBlock('Phase3 Update Before');

        $response = $this->putJson("/api/block-manager/{$block->id}", [
            'name'           => 'Phase3 Update After',
            'structure_json' => ['elements' => [['instance_id' => 'el-x', 'element_type' => 'paragraph', 'variant' => 'default']]],
        ]);
        $response->assertStatus(200);

        $fresh = BlockManagerBlock::find($block->id);
        $this->assertSame('Phase3 Update After', $fresh->name);
        $this->assertSame('paragraph', $fresh->structure_json['elements'][0]['element_type']);
    }

    public function test_update_returns_404_for_unknown_id(): void
    {
        $this->putJson('/api/block-manager/99999999', ['name' => 'nope'])->assertStatus(404);
    }

    public function test_destroy_removes_block(): void
    {
        $block = $this->seedBlock('Phase3 Destroy');
        $id = $block->id;

        $this->deleteJson("/api/block-manager/{$id}")->assertStatus(204);

        $this->assertNull(BlockManagerBlock::find($id));
        // Already deleted — remove from cleanup list
        $this->createdUuids = array_filter($this->createdUuids, fn ($u) => $u !== $block->uuid);
    }

    public function test_destroy_returns_404_for_unknown_id(): void
    {
        $this->deleteJson('/api/block-manager/99999999')->assertStatus(404);
    }

    public function test_duplicate_creates_copy_with_new_slug_and_uuid(): void
    {
        $block = $this->seedBlock('Phase3 Original', [
            'elements' => [['instance_id' => 'el-1', 'element_type' => 'button', 'variant' => 'primary']],
        ]);

        $response = $this->postJson("/api/block-manager/{$block->id}/duplicate");
        $response->assertStatus(201);

        $copy = $response->json('data');
        $this->createdUuids[] = $copy['uuid'];

        $this->assertNotSame($block->uuid, $copy['uuid'], 'Duplicate must have a new uuid.');
        $this->assertNotSame($block->slug, $copy['slug'], 'Duplicate must have a different slug.');
        $this->assertSame('button', $copy['structure_json']['elements'][0]['element_type']);

        // Original survives
        $original = BlockManagerBlock::find($block->id);
        $this->assertNotNull($original);
        $this->assertSame($block->slug, $original->slug);
    }

    public function test_duplicate_returns_404_for_unknown_id(): void
    {
        $this->postJson('/api/block-manager/99999999/duplicate')->assertStatus(404);
    }

    private function seedBlock(string $name, ?array $structure = null): BlockManagerBlock
    {
        $uuid = (string) Str::uuid();
        $this->createdUuids[] = $uuid;

        return BlockManagerBlock::create([
            'uuid'           => $uuid,
            'slug'           => Str::slug($name) . '-' . Str::random(6),
            'name'           => $name,
            'structure_json' => $structure ?? ['elements' => []],
        ]);
    }
}
