<?php

namespace Mtc\Plugins\BlockManager\Http\Controllers;

use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
use Mtc\Modules\BlockRegistry\Models\BlockRegistryField;
use Mtc\Plugins\BlockManager\Models\BlockManagerBlock;
use Mtc\Plugins\BlockManager\Services\BlockPreviewService;
use Mtc\Plugins\BlockManager\Services\ViteAssetResolver;

/**
 * CRUD for composed-block drafts. Stateless JSON; extends Laravel's base routing
 * controller directly to avoid the project base class's admin-session bootstrap.
 */
class BlockManagerController extends Controller
{
    /**
     * Render an in-memory composed-block structure to HTML for the Composer's
     * live canvas, plus the site app.css href(s) the canvas iframe loads so the
     * real element-variant styles apply. Works on unsaved structure, so the
     * canvas updates live before the block is saved.
     */
    public function preview(Request $request, BlockPreviewService $preview, ViteAssetResolver $vite): JsonResponse
    {
        $structure = $request->input('structure_json');
        if (!is_array($structure)) {
            $structure = ['elements' => []];
        }

        return response()->json([
            'data' => [
                'html'      => $preview->render($structure),
                'css'       => $preview->collectStyleCss($structure),
                'css_hrefs' => $vite->css('sites/default/js/app.js'),
            ],
        ]);
    }

    public function index(): JsonResponse
    {
        return response()->json([
            'data' => BlockManagerBlock::orderBy('id')->get()->all(),
        ]);
    }

    public function show(int $id): JsonResponse
    {
        $block = BlockManagerBlock::findOrFail($id);
        return response()->json(['data' => $block]);
    }

    public function store(Request $request): JsonResponse
    {
        $data = $request->validate([
            'name'           => 'required|string|max:255',
            'slug'           => 'nullable|string|max:255|unique:block_manager_blocks,slug',
            'description'    => 'nullable|string',
            'icon'           => 'nullable|string|max:100',
            'category_id'    => 'nullable|integer',
            'structure_json' => 'nullable|array',
            'structure_json.fields_panel.custom.*.type' => $this->customFieldTypeRule(),
        ]);

        $block = BlockManagerBlock::create([
            'uuid'           => (string) Str::uuid(),
            'slug'           => $data['slug'] ?? $this->generateUniqueSlug($data['name']),
            'name'           => $data['name'],
            'description'    => $data['description'] ?? null,
            'icon'           => $data['icon'] ?? null,
            'category_id'    => $data['category_id'] ?? null,
            'structure_json' => $data['structure_json'] ?? ['elements' => []],
        ]);

        return response()->json(['data' => $block], 201);
    }

    public function update(Request $request, int $id): JsonResponse
    {
        $block = BlockManagerBlock::findOrFail($id);

        // Slug lock: once shipped, the slug is immutable (per scope §13).
        if ($block->last_shipped_at !== null && $request->has('slug')) {
            $requested = $request->input('slug');
            if ($requested !== $block->slug) {
                throw ValidationException::withMessages([
                    'slug' => 'Slug is locked: this block has already been shipped.',
                ]);
            }
        }

        $data = $request->validate([
            'name'           => 'sometimes|string|max:255',
            'slug'           => 'sometimes|string|max:255|unique:block_manager_blocks,slug,' . $block->id,
            'description'    => 'nullable|string',
            'icon'           => 'nullable|string|max:100',
            'category_id'    => 'nullable|integer',
            'structure_json' => 'nullable|array',
            'structure_json.fields_panel.custom.*.type' => $this->customFieldTypeRule(),
        ]);

        $block->fill($data)->save();

        return response()->json(['data' => $block]);
    }

    /**
     * Laravel validation rule string ensuring custom-field types come from
     * BlockRegistryField::FIELD_TYPES. Triggered only when the nested key path
     * exists, so requests without a fields_panel are unaffected.
     */
    private function customFieldTypeRule(): string
    {
        return 'sometimes|string|in:' . implode(',', array_keys(BlockRegistryField::FIELD_TYPES));
    }

    public function destroy(int $id): JsonResponse
    {
        $block = BlockManagerBlock::findOrFail($id);
        $block->delete();
        return response()->json(null, 204);
    }

    public function duplicate(int $id): JsonResponse
    {
        $original = BlockManagerBlock::findOrFail($id);

        $copy = BlockManagerBlock::create([
            'uuid'           => (string) Str::uuid(),
            'slug'           => $this->generateDuplicateSlug($original->slug),
            'name'           => $original->name . ' (copy)',
            'description'    => $original->description,
            'icon'           => $original->icon,
            'category_id'    => $original->category_id,
            'structure_json' => $original->structure_json ?? ['elements' => []],
        ]);

        return response()->json(['data' => $copy], 201);
    }

    private function generateUniqueSlug(string $name): string
    {
        $base = Str::slug($name) ?: 'block';
        return $this->firstFreeSlug($base);
    }

    private function generateDuplicateSlug(string $originalSlug): string
    {
        return $this->firstFreeSlug($originalSlug . '-copy');
    }

    private function firstFreeSlug(string $base): string
    {
        $candidate = $base;
        $n = 2;
        while (BlockManagerBlock::where('slug', $candidate)->exists()) {
            $candidate = $base . '-' . $n;
            $n++;
        }
        return $candidate;
    }
}
