<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\McpServer\Projects\Console;

use Butschster\ContextGenerator\Application\AppScope;
use Butschster\ContextGenerator\Application\FSPath;
use Butschster\ContextGenerator\Config\ConfigurationProvider;
use Butschster\ContextGenerator\Config\Exception\ConfigLoaderException;
use Butschster\ContextGenerator\Console\BaseCommand;
use Butschster\ContextGenerator\DirectoriesInterface;
use Butschster\ContextGenerator\McpServer\Projects\ProjectServiceInterface;
use Spiral\Console\Attribute\Argument;
use Spiral\Console\Attribute\AsCommand;
use Spiral\Console\Attribute\Option;
use Spiral\Core\Container;
use Spiral\Core\Scope;
use Spiral\Files\FilesInterface;
use Symfony\Component\Console\Command\Command;

#[AsCommand(
    name: 'project:add',
    description: 'Add an additional project context',
)]
final class ProjectAddCommand extends BaseCommand
{
    #[Argument(
        name: 'path',
        description: 'Path to the project directory. Use "." for current directory',
    )]
    protected string $path;

    #[Option(
        name: 'name',
        description: 'Alias name for the project',
    )]
    protected ?string $name = null;

    #[Option(
        name: 'config-file',
        shortcut: 'c',
        description: 'Path to custom configuration file within the project',
    )]
    protected ?string $configFile = null;

    #[Option(
        name: 'env-file',
        shortcut: 'e',
        description: 'Path to .env file within the project',
    )]
    protected ?string $envFile = null;

    #[Option(
        name: 'switch',
        shortcut: 's',
        description: 'Switch to this project after adding it',
    )]
    protected bool $switch = false;

    public function __invoke(
        Container $container,
        DirectoriesInterface $dirs,
        FilesInterface $files,
        ProjectServiceInterface $projectService,
        ConfigurationProvider $configProvider,
    ): int {
        // Handle using an alias as the path
        $resolvedPath = $projectService->resolvePathOrAlias($this->path);
        if ($resolvedPath !== $this->path) {
            $this->logger->info(\sprintf("Resolved alias '%s' to path: %s", $this->path, $resolvedPath));
            $this->path = $resolvedPath;
        }

        // Normalize path to absolute path
        $projectPath = $this->normalizePath($this->path, $dirs);

        // Validate project path
        if (!$files->exists($projectPath)) {
            $this->output->error(\sprintf("Project path does not exist: %s", $projectPath));
            return Command::FAILURE;
        }

        if (!$files->isDirectory($projectPath)) {
            $this->output->error(\sprintf("Project path is not a directory: %s", $projectPath));
            return Command::FAILURE;
        }

        // Validate env file path if provided
        if ($this->envFile !== null) {
            $envPath = FSPath::create($projectPath)->join($this->envFile)->toString();
            if (!$files->exists($envPath)) {
                $this->output->warning(\sprintf("Env file does not exist: %s", $envPath));
                // Not returning failure here, just warning the user
            }
        }

        try {
            // Create temporary directories to test config loading
            $tempDirs = $dirs->determineRootPath(null, null)->withRootPath($projectPath);

            $container->runScope(
                bindings: new Scope(
                    name: AppScope::Compiler,
                    bindings: [
                        DirectoriesInterface::class => $tempDirs,
                    ],
                ),
                scope: static function () use ($configProvider): void {
                    $configProvider->fromDefaultLocation()->load();
                },
            );
        } catch (ConfigLoaderException $e) {
            $this->output->error(
                \sprintf(
                    "No valid context configuration found in %s: %s",
                    $projectPath,
                    $e->getMessage(),
                ),
            );
            return Command::FAILURE;
        }

        // Add the project
        $projectService->addProject($projectPath, $this->name, $this->configFile, $this->envFile);

        $this->output->success(\sprintf("Added project: %s", $projectPath));

        if ($this->name) {
            $this->output->info(\sprintf("Project alias '%s' has been set", $this->name));
        }

        if ($this->envFile) {
            $this->output->info(\sprintf("Project env file '%s' has been set", $this->envFile));
        }

        // If this is the first project, also set it as the current project
        if (\count($projectService->getProjects()) === 1) {
            $projectService->setCurrentProject($projectPath, $this->name, $this->configFile, $this->envFile);
            $this->output->info('Project was automatically set as the current project (first project added).');
        }
        // If --switch flag is set for subsequent projects, switch to it
        elseif ($this->switch) {
            if ($projectService->switchToProject($projectPath)) {
                $this->output->info('Successfully switched to this project.');
            } else {
                $this->output->warning(
                    \sprintf(
                        "Project added but failed to switch. Use 'ctx project %s' to switch manually.",
                        $this->name ?? $projectPath,
                    ),
                );
            }
        }

        return Command::SUCCESS;
    }

    /**
     * Normalize a path to an absolute path
     */
    private function normalizePath(string $path, DirectoriesInterface $dirs): string
    {
        // Handle special case for current directory
        if ($path === '.') {
            return (string) FSPath::cwd();
        }

        $pathObj = FSPath::create($path);

        // If path is relative, make it absolute from the current directory
        if ($pathObj->isRelative()) {
            $pathObj = $pathObj->absolute();
        }

        return $pathObj->toString();
    }
}
