<?php

declare(strict_types=1);

namespace PpPhp\Core\Databases\Drivers;

/**
 * Builds the right provisioning driver for a server row.
 *
 * The one rule that keeps this safe to add to a live system: an unknown, empty
 * or missing `driver` resolves to `sql`. Every server registered before the
 * panel drivers existed therefore behaves exactly as it did before — the new
 * code is additive, never a change of default.
 */
final class DriverFactory
{
    public const SQL          = 'sql';
    public const CPANEL       = 'cpanel';
    public const DIRECTADMIN  = 'directadmin';

    /** @return array<string,string> id => human label, for the owner UI */
    public static function options(): array
    {
        return [
            self::SQL         => 'Direct MySQL (VPS / local — needs CREATE privilege)',
            self::CPANEL      => 'cPanel API (shared hosting)',
            self::DIRECTADMIN => 'DirectAdmin API (shared hosting)',
        ];
    }

    public static function normalise(?string $id): string
    {
        $id = strtolower(trim((string) $id));
        return in_array($id, [self::CPANEL, self::DIRECTADMIN], true) ? $id : self::SQL;
    }

    /** Default panel port for a driver, used to prefill the form. */
    public static function defaultPort(string $driver): int
    {
        return match (self::normalise($driver)) {
            self::CPANEL      => 2083,
            self::DIRECTADMIN => 2222,
            default           => 3306,
        };
    }

    /**
     * @param array<string,mixed> $server a `pp_db_servers` row, or the platform
     *                                    row already merged with config creds
     */
    public static function make(array $server): ProvisionDriver
    {
        $driver = self::normalise((string) ($server['driver'] ?? self::SQL));
        $host   = (string) ($server['host'] ?? '127.0.0.1');
        $user   = (string) ($server['admin_user'] ?? '');
        $secret = (string) ($server['admin_pass'] ?? '');       // token / login key / password
        $port   = (int) ($server['api_port'] ?? 0);
        $dbHost = (string) ($server['db_host'] ?? '');
        $dbPort = (int) ($server['port'] ?? 3306);

        return match ($driver) {
            self::CPANEL => new CpanelDriver(
                $host, $user, $secret,
                $port ?: 2083,
                $dbHost !== '' ? $dbHost : 'localhost',
                $dbPort ?: 3306
            ),
            self::DIRECTADMIN => new DirectAdminDriver(
                $host, $user, $secret,
                $port ?: 2222,
                $dbHost !== '' ? $dbHost : 'localhost',
                $dbPort ?: 3306
            ),
            default => new SqlDriver(
                $host, $dbPort ?: 3306, $user, $secret,
                (string) ($server['grant_host'] ?? '%')
            ),
        };
    }

    /** Does this driver authenticate with an API token/key rather than a DB password? */
    public static function usesApiToken(string $driver): bool
    {
        return self::normalise($driver) !== self::SQL;
    }
}
