<?php

namespace Mtc\Plugins\BlockManager\Services;

use Mtc\Plugins\BlockManager\Models\BlockManagerVariantDraft;

/**
 * Materialises a Designer variant draft into the on-disk element catalogue.
 *
 * Four-step pipeline:
 *   1. Generate Twig partial at  elements/{type}/variants/{slug}.twig
 *   2. Generate LESS stylesheet at elements/{type}/styles/{slug}.less
 *   3. Patch the element's manifest (variants[])
 *   4. Update the draft's audit fields (last_published_at, published_*_path)
 *
 * Idempotent by `(element_type, variant_slug)` — re-publishing rewrites the
 * files in place and updates the manifest entry without duplicating it.
 */
class VariantPublishService
{
    public function __construct(
        private VariantTwigGenerator $twig,
        private VariantLessGenerator $less,
        private VariantManifestPatcher $manifest,
        private VariantStyleAggregator $styleAggregator,
    ) {
    }

    /**
     * @return array{twig_path: string, less_path: string, manifest_path: string, last_published_at: string}
     */
    public function publish(BlockManagerVariantDraft $draft): array
    {
        $variantsDir = base_path("plugins/BlockManager/elements/{$draft->element_type}/variants");
        $stylesDir   = base_path("plugins/BlockManager/elements/{$draft->element_type}/styles");

        if (!is_dir($variantsDir)) {
            @mkdir($variantsDir, 0775, true);
        }
        if (!is_dir($stylesDir)) {
            @mkdir($stylesDir, 0775, true);
        }

        $twigPath = "{$variantsDir}/{$draft->variant_slug}.twig";
        $lessPath = "{$stylesDir}/{$draft->variant_slug}.less";

        // Roll the prior file (if any) into .bak before overwriting — one-cycle
        // retention so a republish never silently destroys hand-edits. POSIX
        // rename atomically overwrites any existing .bak.
        $this->backupIfExists($twigPath);
        $this->backupIfExists($lessPath);

        file_put_contents($twigPath, $this->twig->generate($draft));
        file_put_contents($lessPath, $this->less->generate($draft));
        $manifestPath = $this->manifest->patch($draft);

        // Wire the (possibly new) variant stylesheet into the frontend build
        // so the published block is actually styled on the site.
        $this->styleAggregator->rebuild();

        $draft->last_published_at = now();
        $draft->published_twig_path = $twigPath;
        $draft->published_less_path = $lessPath;
        $draft->save();

        return [
            'twig_path'         => $twigPath,
            'less_path'         => $lessPath,
            'manifest_path'     => $manifestPath,
            'last_published_at' => $draft->last_published_at->toIso8601String(),
        ];
    }

    private function backupIfExists(string $path): void
    {
        if (is_file($path)) {
            @rename($path, "{$path}.bak");
        }
    }
}
