<?php

declare(strict_types=1);

namespace App\Shared\Infrastructure\Tenant\Command;

use Doctrine\DBAL\DriverManager;
use Override;

use function sprintf;

use Symfony\Component\Console\Attribute\AsCommand;
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Style\SymfonyStyle;
use Throwable;

#[AsCommand(
    name: 'tenant:database:create',
    description: 'Creates a new database for a tenant'
)]
final class CreateTenantDatabaseCommand extends Command
{
    public function __construct(
        private readonly string $masterDatabaseUrl,
    ) {
        parent::__construct();
    }

    #[Override]
    protected function configure(): void
    {
        $this
            ->addArgument('database_name', InputArgument::REQUIRED, 'The name of the database to create (e.g., classeo_tenant_alpha)')
            ->addArgument('database_user', InputArgument::OPTIONAL, 'The database user to grant access to', 'classeo')
        ;
    }

    #[Override]
    protected function execute(InputInterface $input, OutputInterface $output): int
    {
        $io = new SymfonyStyle($input, $output);

        /** @var string $databaseName */
        $databaseName = $input->getArgument('database_name');
        /** @var string $databaseUser */
        $databaseUser = $input->getArgument('database_user');

        // Validate database name format
        if (!preg_match('/^classeo_tenant_[a-z0-9_]+$/', $databaseName)) {
            $io->error('Database name must follow pattern: classeo_tenant_<name>');

            return Command::FAILURE;
        }

        $io->title("Creating database: {$databaseName}");

        try {
            // Connect to master database (postgres) to create new database
            $connection = DriverManager::getConnection(['url' => $this->masterDatabaseUrl]);

            // Check if database already exists
            $existsQuery = $connection->executeQuery(
                'SELECT 1 FROM pg_database WHERE datname = :name',
                ['name' => $databaseName]
            );

            if ($existsQuery->fetchOne() !== false) {
                $io->warning("Database '{$databaseName}' already exists.");

                return Command::SUCCESS;
            }

            // Create database
            // Note: Database names cannot be parameterized in SQL, so we use a validated name
            $connection->executeStatement(sprintf(
                'CREATE DATABASE %s WITH OWNER = %s ENCODING = \'UTF8\' LC_COLLATE = \'en_US.utf8\' LC_CTYPE = \'en_US.utf8\'',
                $this->quoteIdentifier($databaseName),
                $this->quoteIdentifier($databaseUser)
            ));

            $io->success("Database '{$databaseName}' created successfully.");

            return Command::SUCCESS;
        } catch (Throwable $e) {
            $io->error([
                'Failed to create database',
                $e->getMessage(),
            ]);

            return Command::FAILURE;
        }
    }

    private function quoteIdentifier(string $identifier): string
    {
        // Simple identifier quoting for PostgreSQL
        return '"' . str_replace('"', '""', $identifier) . '"';
    }
}
