<?php

declare(strict_types=1);

namespace Builder\Core\Foundation\Commands;

use Builder\Core\Foundation\Definition\JsModule;
use Builder\Core\Foundation\Registry;
use Illuminate\Console\Command;

final class LinkCommand extends Command
{
    protected $signature = 'builder:link
        {--source= : Override the source directory (default: auto-detected from package location)}
        {--target= : Override the target symlink path (default: public/vendor/builder/core)}';

    protected $description = 'Create symbolic links for Builder core and all registered module packages';

    public function handle(Registry $registry): int
    {
        $exitCode = $this->linkCore();

        if ($exitCode !== self::SUCCESS) {
            return $exitCode;
        }

        foreach ($registry->all() as $module) {
            if ($module->getPublicPath() === null) {
                continue;
            }

            $this->linkModule($module);
        }

        return self::SUCCESS;
    }

    private function linkCore(): int
    {
        $source = $this->resolveSource();

        if (! is_dir($source)) {
            $this->error("Source directory [{$source}] does not exist.");

            return self::FAILURE;
        }

        $target = $this->resolveTarget();

        return $this->createLink($source, $target);
    }

    private function linkModule(JsModule $module): void
    {
        $source = (string) $module->getPublicPath();
        $target = public_path('vendor/builder/'.$module->getKey());

        if (! is_dir($source)) {
            $this->warn("Skipping module '{$module->getKey()}': public path [{$source}] does not exist.");

            return;
        }

        $this->createLink($source, $target);
    }

    private function createLink(string $source, string $target): int
    {
        $parent = dirname($target);
        if (! is_dir($parent)) {
            mkdir($parent, 0755, true);
        }

        if (is_link($target)) {
            unlink($target);
        } elseif (file_exists($target)) {
            $this->error("[{$target}] already exists and is not a symlink. Remove it first.");

            return self::FAILURE;
        }

        symlink($source, $target);
        $this->info("Builder assets linked: [{$target}] → [{$source}].");

        return self::SUCCESS;
    }

    private function resolveSource(): string
    {
        /** @var string|null $override */
        $override = $this->option('source');

        return $override ?? (string) (realpath(__DIR__.'/../../../public') ?: '');
    }

    private function resolveTarget(): string
    {
        /** @var string|null $override */
        $override = $this->option('target');

        return $override ?? public_path('vendor/builder/core');
    }
}
