<?php

namespace App\Commands;

use App\Services\Command;
use App\Services\ProjectCreator;
use App\Services\ProjectDoctor;
use Symfony\Component\Console\Command\Command as SymfonyCommand;
use function Laravel\Prompts\error;
use function Laravel\Prompts\info;
use function Laravel\Prompts\text;

class Create extends Command
{
    protected $signature = 'create
        {directory? : Target directory for the new project}
        {--repository= : Git remote to add as origin}
        {--slug= : Project slug used for local defaults}
        {--url= : Local project url}
        {--db-name= : Database name}
        {--db-host=host.db.docker.internal:7689 : Database host with port}
        {--starter-repo=git@github.com:probots-io/probots-wp-starter-2024.git : Starter repository to clone}';

    protected $description = 'Create a new project from the starter';

    public function handle(ProjectCreator $creator, ProjectDoctor $doctor): int
    {
        $projectDir = $this->resolveProjectDir();

        try {
            $creator->ensureUsableTargetDirectory($projectDir);
        } catch (\RuntimeException $exception) {
            error($exception->getMessage());

            return SymfonyCommand::FAILURE;
        }

        $slug = $this->optionOrPrompt('slug', 'Project slug', basename($projectDir));
        $repositoryUrl = $this->optionOrPrompt('repository', 'Repository ssh url', '');
        $url = $this->optionOrPrompt('url', 'Local url', $slug . '.prbts');
        $dbName = $this->optionOrPrompt('db-name', 'Database name', $slug);
        $dbHost = $this->optionOrPrompt('db-host', 'Database host', 'host.db.docker.internal:7689');

        try {
            info('Cloning starter...');
            $creator->cloneStarter((string) $this->option('starter-repo'), $projectDir);

            info('Initializing git...');
            $creator->initializeGit($projectDir, $repositoryUrl);

            info('Writing .env...');
            $creator->writeEnv($projectDir, $creator->buildEnvValues($slug, $url, $dbName, $dbHost));

            info('Running doctor checks...');
            $results = $creator->doctor($projectDir);
            $this->renderDoctorResults($results);

            if ($doctor->hasErrors($results)) {
                return SymfonyCommand::FAILURE;
            }

            info('Starting project services and installing dependencies...');
            $creator->install($projectDir);

            info(sprintf('Project ready at http://%s', $url));
            info(sprintf('Project directory: %s', $projectDir));

            return SymfonyCommand::SUCCESS;
        } catch (\Throwable $exception) {
            error($exception->getMessage());

            return SymfonyCommand::FAILURE;
        }
    }

    private function resolveProjectDir(): string
    {
        $directory = $this->argument('directory');

        if (!is_string($directory) || $directory === '') {
            return getcwd();
        }

        if (str_starts_with($directory, '/')) {
            return $directory;
        }

        return getcwd() . '/' . $directory;
    }

    private function optionOrPrompt(string $option, string $label, string $default): string
    {
        $value = $this->option($option);

        if (is_string($value) && $value !== '') {
            return $value;
        }

        return text(
            label: $label,
            default: $default,
            required: true,
        );
    }

    private function renderDoctorResults(array $results): void
    {
        foreach ($results as $result) {
            $prefix = match ($result['status']) {
                'ok' => 'OK',
                'warning' => 'WARN',
                default => 'ERR',
            };

            $this->line(sprintf('[%s] %s: %s', $prefix, $result['label'], $result['message']));
        }
    }
}
