<?php

namespace Mtc\Plugins\BlockManager\Tests\Feature;

use Illuminate\Support\Str;
use Mtc\Modules\BlockRegistry\Models\BlockRegistry;
use Mtc\Modules\BlockRegistry\Services\BlockSyncService;
use Mtc\Plugins\BlockManager\Models\BlockManagerBlock;
use Tests\TestCase;

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

    /** @var string[] */
    private array $shippedSlugs = [];

    protected function tearDown(): void
    {
        $twigDir = base_path('sites/default/templates/includes/page_blocks');
        $jsonDir = base_path('modules/BlockRegistry/blocks');

        foreach ($this->shippedSlugs as $slug) {
            @unlink($twigDir . "/{$slug}.twig");
            @unlink($jsonDir . "/{$slug}.json");
            BlockRegistry::where('slug', $slug)->delete();
        }

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

        parent::tearDown();
    }

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

    public function test_ship_returns_success_envelope(): void
    {
        $block = $this->seedShipableBlock();

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

        $payload = $response->json('data');
        $this->assertIsArray($payload);
        foreach (['block_registry_id', 'slug', 'twig_path', 'json_path'] as $key) {
            $this->assertArrayHasKey(
                $key,
                $payload,
                "Ship response 'data' is missing '{$key}'."
            );
        }

        $this->shippedSlugs[] = $payload['slug'];
        $this->assertIsInt($payload['block_registry_id']);
        $this->assertNotEmpty($payload['slug']);
    }

    public function test_ship_writes_twig_template_to_disk(): void
    {
        $block = $this->seedShipableBlock();

        $this->postJson("/api/block-manager/{$block->id}/ship")->assertStatus(200);
        $this->shippedSlugs[] = $block->slug;

        $twigPath = base_path("sites/default/templates/includes/page_blocks/{$block->slug}.twig");
        $this->assertFileExists(
            $twigPath,
            "Generated Twig template was not written to {$twigPath}."
        );
    }

    public function test_ship_twig_references_each_element_variant_partial(): void
    {
        $block = $this->seedShipableBlock();

        $this->postJson("/api/block-manager/{$block->id}/ship")->assertStatus(200);
        $this->shippedSlugs[] = $block->slug;

        $twig = file_get_contents(
            base_path("sites/default/templates/includes/page_blocks/{$block->slug}.twig")
        );

        $this->assertStringContainsString(
            'heading/variants/default.twig',
            $twig,
            'Generated Twig does not include the heading default variant partial.'
        );
        $this->assertStringContainsString(
            'button/variants/primary.twig',
            $twig,
            'Generated Twig does not include the button primary variant partial.'
        );
    }

    public function test_ship_writes_block_registry_json_to_disk(): void
    {
        $block = $this->seedShipableBlock();

        $this->postJson("/api/block-manager/{$block->id}/ship")->assertStatus(200);
        $this->shippedSlugs[] = $block->slug;

        $jsonPath = base_path("modules/BlockRegistry/blocks/{$block->slug}.json");
        $this->assertFileExists($jsonPath, "JSON file not written to {$jsonPath}.");

        $decoded = json_decode((string) file_get_contents($jsonPath), true);
        $this->assertIsArray($decoded);

        foreach (['name', 'slug', 'template', 'fields', 'category', 'template_assignments'] as $key) {
            $this->assertArrayHasKey($key, $decoded, "BlockRegistry JSON is missing '{$key}'.");
        }
    }

    public function test_ship_json_template_path_is_page_blocks_slug(): void
    {
        $block = $this->seedShipableBlock();

        $this->postJson("/api/block-manager/{$block->id}/ship")->assertStatus(200);
        $this->shippedSlugs[] = $block->slug;

        $decoded = json_decode((string) file_get_contents(
            base_path("modules/BlockRegistry/blocks/{$block->slug}.json")
        ), true);

        $this->assertSame("page_blocks/{$block->slug}.twig", $decoded['template']);
    }

    public function test_ship_registers_row_in_block_registry_table(): void
    {
        $block = $this->seedShipableBlock();

        $this->postJson("/api/block-manager/{$block->id}/ship")->assertStatus(200);
        $this->shippedSlugs[] = $block->slug;

        $registered = BlockRegistry::where('slug', $block->slug)->first();
        $this->assertNotNull($registered, 'BlockRegistry row was not created.');
        $this->assertSame("page_blocks/{$block->slug}.twig", $registered->template);
    }

    public function test_ship_sets_audit_fields_on_source_block(): void
    {
        $block = $this->seedShipableBlock();

        $response = $this->postJson("/api/block-manager/{$block->id}/ship");
        $response->assertStatus(200);
        $this->shippedSlugs[] = $block->slug;

        $fresh = BlockManagerBlock::find($block->id);
        $this->assertNotNull($fresh->last_shipped_at, 'last_shipped_at should be populated.');
        $this->assertNotNull(
            $fresh->shipped_block_registry_id,
            'shipped_block_registry_id should reference the new BlockRegistry row.'
        );
        $this->assertSame(
            $response->json('data.block_registry_id'),
            $fresh->shipped_block_registry_id
        );
    }

    public function test_ship_is_idempotent_on_resave(): void
    {
        $block = $this->seedShipableBlock();

        $first = $this->postJson("/api/block-manager/{$block->id}/ship");
        $first->assertStatus(200);
        $this->shippedSlugs[] = $block->slug;
        $firstId = $first->json('data.block_registry_id');

        $second = $this->postJson("/api/block-manager/{$block->id}/ship");
        $second->assertStatus(200);
        $secondId = $second->json('data.block_registry_id');

        $this->assertSame($firstId, $secondId, 'Re-shipping must not create a duplicate BlockRegistry row.');
        $this->assertSame(1, BlockRegistry::where('slug', $block->slug)->count());
    }

    public function test_ship_imports_cleanly_via_block_sync_service(): void
    {
        $block = $this->seedShipableBlock();

        $this->postJson("/api/block-manager/{$block->id}/ship")->assertStatus(200);
        $this->shippedSlugs[] = $block->slug;

        $jsonPath = base_path("modules/BlockRegistry/blocks/{$block->slug}.json");
        $sync = app(BlockSyncService::class);

        $data = $sync->readBlockFile($jsonPath);
        $errors = $sync->validateBlockJson($data);

        $this->assertSame(
            [],
            $errors,
            'Shipped JSON failed BlockSyncService validation: ' . json_encode($errors)
        );
    }

    /**
     * Seeds a BlockManagerBlock with a heading + button structure that exercises
     * the Phase 2 element manifests already on disk.
     */
    private function seedShipableBlock(): BlockManagerBlock
    {
        $uuid = (string) Str::uuid();
        $this->createdUuids[] = $uuid;

        return BlockManagerBlock::create([
            'uuid'           => $uuid,
            'slug'           => 'phase4-ship-' . Str::random(8),
            'name'           => 'Phase4 Ship Probe',
            'description'    => 'Auto-seeded by ShipApiTest.',
            'icon'           => 'fa-cube',
            'structure_json' => [
                'elements' => [
                    [
                        'instance_id'  => 'el-001',
                        'element_type' => 'heading',
                        'variant'      => 'default',
                        'field_name'   => 'title',
                    ],
                    [
                        'instance_id'  => 'el-002',
                        'element_type' => 'button',
                        'variant'      => 'primary',
                        'field_name'   => 'cta',
                    ],
                ],
            ],
        ]);
    }
}
