<?php

declare(strict_types=1);

namespace App\Framework\Database\Migration\Commands;

use App\Framework\Console\ConsoleCommand;
use App\Framework\Console\ExitCode;
use App\Framework\Core\PathProvider;
use App\Framework\Database\DatabaseManager;
use App\Framework\Database\Migration\MigrationVersion;
use App\Framework\Database\Schema\Comparison\MigrationGenerator;
use App\Framework\Database\Schema\Comparison\SchemaComparator;

/**
 * Command to generate a migration from schema differences between two databases
 */
final readonly class MakeMigrationFromDiffCommand
{
    public function __construct(
        private DatabaseManager $databaseManager,
        private MigrationGenerator $migrationGenerator,
        private PathProvider $pathProvider
    ) {
    }

    /**
     * Generate a migration from schema differences
     *
     * @param string $name The name of the migration
     * @param string $sourceConnection The name of the source connection (default: default)
     * @param string $targetConnection The name of the target connection
     * @param string|null $sourceSchema The name of the source schema (default: public for PostgreSQL, database name for MySQL)
     * @param string|null $targetSchema The name of the target schema (default: public for PostgreSQL, database name for MySQL)
     * @param string $domain The domain for the migration (default: Media)
     * @return ExitCode
     */
    #[ConsoleCommand('db:migrate:diff', 'Generate a migration from schema differences')]
    public function __invoke(
        string $name,
        string $sourceConnection = 'default',
        string $targetConnection = 'default',
        ?string $sourceSchema = null,
        ?string $targetSchema = null,
        string $domain = 'Media'
    ): ExitCode {
        if (empty($name)) {
            echo "Error: Migration name is required\n";
            echo "Usage: db:migrate:diff UpdateUserTable [sourceConnection] [targetConnection] [sourceSchema] [targetSchema] [domain]\n";

            return ExitCode::INVALID_ARGUMENT;
        }

        try {
            // Get the connections
            $sourceConn = $this->databaseManager->getConnection($sourceConnection);
            $targetConn = $this->databaseManager->getConnection($targetConnection);

            // Compare the schemas
            $comparator = new SchemaComparator($sourceConn, $targetConn);
            $difference = $comparator->compare($sourceSchema, $targetSchema);

            if (! $difference->hasDifferences()) {
                echo "No schema differences found.\n";

                return ExitCode::SUCCESS;
            }

            // Generate the migration
            $className = $this->toClassName($name);
            $version = MigrationVersion::fromDateTime(new \DateTimeImmutable());
            $description = $name;

            $migrationCode = $this->migrationGenerator->generateMigration(
                $difference,
                $className,
                $description,
                $version
            );

            // Save the migration to a file
            $migrationPath = $this->pathProvider->resolvePath("src/Domain/{$domain}/Migrations");

            if (! is_dir($migrationPath)) {
                mkdir($migrationPath, 0755, true);
            }

            $fileName = "{$className}.php";
            $filePath = $migrationPath . '/' . $fileName;

            if (file_exists($filePath)) {
                echo "Error: Migration file already exists: {$filePath}\n";

                return ExitCode::SOFTWARE_ERROR;
            }

            file_put_contents($filePath, $migrationCode);
            echo "Migration created: {$filePath}\n";

            // Display a summary of the differences
            echo "\nSchema Difference Summary:\n";
            echo str_repeat('-', 80) . "\n";

            $summary = $difference->getSummary();
            echo "Missing tables: {$summary['missing_tables']}\n";
            echo "Extra tables: {$summary['extra_tables']}\n";
            echo "Modified tables: " . count($difference->tableDifferences) . "\n";

            echo "\nFor detailed differences, use the db:schema:diff command.\n";

            return ExitCode::SUCCESS;
        } catch (\Throwable $e) {
            echo "Error creating migration: {$e->getMessage()}\n";
            if (isset($_ENV['APP_DEBUG']) && $_ENV['APP_DEBUG']) {
                echo $e->getTraceAsString() . "\n";
            }

            return ExitCode::SOFTWARE_ERROR;
        }
    }

    /**
     * Convert a string to a class name
     */
    private function toClassName(string $name): string
    {
        // Convert "Create Users Table" to "CreateUsersTable"
        return str_replace(' ', '', ucwords(str_replace('_', ' ', $name)));
    }
}
