<?php

declare(strict_types=1);

namespace Maestro\Core\Services;

use Illuminate\Support\Facades\File;
use Maestro\Core\Support\PackagePaths;

/**
 * Copies package stubs into the host Laravel application.
 */
final class StubPublisher
{
    public const MANAGED_BANNER = '@maestro-core-managed';

    /**
     * @param  array<string, string>  $map  stub path under stubs/ => project-relative destination
     * @return list<string> Project-relative paths that were written
     */
    public function publishManaged(array $map, bool $force): array
    {
        $written = [];

        foreach ($map as $stubRelative => $destinationRelative) {
            if ($this->copyStub($stubRelative, $destinationRelative, $force, managed: true)) {
                $written[] = $destinationRelative;
            }
        }

        return $written;
    }

    /**
     * Host-owned stubs: copy only when the destination file does not exist.
     *
     * @param  array<string, string>  $map
     * @return list<string>
     */
    public function publishCustom(array $map): array
    {
        $written = [];

        foreach ($map as $stubRelative => $destinationRelative) {
            if ($this->copyStub($stubRelative, $destinationRelative, force: false, managed: false)) {
                $written[] = $destinationRelative;
            }
        }

        return $written;
    }

    /**
     * Overwrite host-owned stubs (e.g. cursor rules refresh).
     *
     * @param  array<string, string>  $map
     * @return list<string>
     */
    public function publishCustomOverwrite(array $map): array
    {
        $written = [];

        foreach ($map as $stubRelative => $destinationRelative) {
            if ($this->copyStub($stubRelative, $destinationRelative, force: true, managed: false)) {
                $written[] = $destinationRelative;
            }
        }

        return $written;
    }

    private function copyStub(
        string $stubRelative,
        string $destinationRelative,
        bool $force,
        bool $managed,
    ): bool {
        $source = PackagePaths::stubPath($stubRelative);
        $destination = base_path($destinationRelative);

        if (! File::exists($source)) {
            return false;
        }

        if ($managed) {
            if (! $this->shouldWriteManagedFile($destination, $force)) {
                return false;
            }
        } elseif (File::exists($destination) && ! $force) {
            return false;
        }

        File::ensureDirectoryExists(dirname($destination));
        File::copy($source, $destination);

        return true;
    }

    private function shouldWriteManagedFile(string $destination, bool $force): bool
    {
        if ($force) {
            return true;
        }

        if (! File::exists($destination)) {
            return true;
        }

        return ! str_contains(File::get($destination), self::MANAGED_BANNER);
    }
}
