#!/usr/bin/env php
<?php

declare(strict_types=1);

use CliArgs\CliArgs;
use Cycle\Database\Config\DatabaseConfig;
use Cycle\Database\Config\MySQL\TcpConnectionConfig;
use Cycle\Database\Config\MySQLDriverConfig;
use Cycle\Database\DatabaseManager;
use Cycle\Migrations\Config\MigrationConfig;
use Cycle\Migrations\FileRepository;
use Cycle\Migrations\Migrator;
use Enqueue\Dsn\Dsn;
use League\Container\Container;
use Monolog\Formatter\LineFormatter;
use Monolog\Handler\ErrorLogHandler;
use Monolog\Logger;
use Monolog\Processor\PsrLogMessageProcessor;
use Spiral\Tokenizer\ClassLocator;
use Swissport\Serverless\Helper\MigrationsHelper;
use Symfony\Component\Finder\Finder;

if (file_exists(__DIR__ . '/vendor/autoload.php')) {
    require_once __DIR__ . '/vendor/autoload.php';
} elseif (file_exists(__DIR__ . '/../autoload.php')) {
    /** @noinspection PhpIncludeInspection */
    require_once __DIR__ . '/../autoload.php';
} else {
    /** @noinspection PhpIncludeInspection */
    require_once __DIR__ . '/../../autoload.php';
}

$config = [
    'migrations_directory' => [
        'alias' => 'm',
        'default' => getcwd() . "/migrations",
        'help' => 'Path in which to place migrations.  Defaults to working directory.',
    ],
    'entities_directory',
        'alias' => 'e',
        'help' => 'Path to entities for which to generate database schemata',
    'verbose' => [
        'alias' => 'v',
        'help' => 'Verbose.',
    ],
    'dsn' => [
        'alias' => 'd',
        'help' => 'DSN to the database for which to generate migrations',
    ],
    'table' => [
        'alias' => 't',
        'help' => 'Name of the table in which migrations are stored',
    ],
    'help' => [
        'alias' => 'h',
        'filter' => 'flag',
        'help' => 'Show help',
    ],
];

$requiredArgs = [
    'migrations_directory',
    'entities_directory',
    'dsn',
    'table',
];

$container = new Container();
$container->defaultToShared(true);

$container->add(CliArgs::class)
    ->addArgument($config);

/** @var CliArgs */
$args = $container->get(CliArgs::class);

switch (true) {
    case ($args->getArg('verbose') == 2):
        $loggerVerbosity = Logger::DEBUG;
        break;
    case ($args->isFlagExist('v')):
        $loggerVerbosity = Logger::INFO;
        break;
    default:
        $loggerVerbosity = Logger::NOTICE;
        break;
}

$lineFormat = "[%datetime%] %message% %context%";
$dateFormat = "Y-m-d H:i:s";

$container->add(LineFormatter::class)
    ->addArguments([$lineFormat, $dateFormat]);
$container->add(ErrorLogHandler::class)
    ->addArguments([ErrorLogHandler::OPERATING_SYSTEM, $loggerVerbosity])
    ->addMethodCall('setFormatter', [LineFormatter::class]);
$container->add(PsrLogMessageProcessor::class);
$container->add(Logger::class)
    ->addArgument('migrations-generator')
    ->addMethodCall('pushHandler', [ErrorLogHandler::class])
    ->addMethodCall('pushProcessor', [PsrLogMessageProcessor::class])
    ->setShared(true);

$container->inflector(LoggerAwareInterface::class)
    ->invokeMethod('setLogger', [Logger::class]);

if ($args->isFlagExist('h')) {
    print $args->getHelp();
    exit;
}

$logger = $container->get(Logger::class);

$missing = [];

foreach ($requiredArgs as $requiredArg) {
    if (!$args->getArg($requiredArg)) {
        $missing[] = $requiredArg;
    }
}

if (!empty($missing)) {
    $logger->critical('Missing arguments: ' . implode(',', $missing));
    exit(1);
}

try {
    $dsn = Dsn::parseFirst($args->getArg('dsn'));
} catch (Exception $e) {
    $logger->critical($e->getMessage());
    exit(1);
}

$dbConfig = new DatabaseConfig([
    'default' => 'default',
    'databases' => [
        'default' => ['connection' => $dsn->getScheme(),]
    ],
    'connections' => [
        'mysql' => new MySQLDriverConfig(
            connection: new TcpConnectionConfig(
                database: str_replace("/", "", $dsn->getPath()),
                host: $dsn->getHost(),
                port: $dsn->getPort(),
                user: $dsn->getUser(),
                password: $dsn->getPassword(),
            ),
            queryCache: true,
        )
    ]
]);

$container->add(DatabaseManager::class)
    ->addArgument($dbConfig)
    ->addMethodCall('setLogger', [$logger]);

$container->add(MigrationConfig::class)
    ->addArgument([
        'directory' => $args->getArg('migrations_directory'),
        'table' => $args->getArg('table'),
        'safe' => true,
    ]);

$container->add(FileRepository::class)
    ->addArgument($container->get(MigrationConfig::class));

$container->add(Migrator::class)
    ->addArgument(MigrationConfig::class)
    ->addArgument(DatabaseManager::class)
    ->addArgument(FileRepository::class)
    ->addMethodCall('configure');

$container->add(Finder::class);

$container->add(ClassLocator::class)
    ->addArgument($container->get(Finder::class)->files()->in(realpath($args->getArg('entities_directory'))));

$container->add(MigrationsHelper::class)
    ->addArgument(DatabaseManager::class)
    ->addArgument(MigrationConfig::class)
    ->addArgument(ClassLocator::class);

$container->get(MigrationsHelper::class)->generateMigrations();