<?php

declare(strict_types=1);

final class ImapProviderCatalog
{
    /** @return array<string,array{host:string,port:int,flags:string,message:string}> */
    public static function providers(): array
    {
        return [
            'Gmail' => [
                'host' => 'imap.gmail.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Usa una contraseña de aplicación de Google; no utilices la contraseña normal de la cuenta.',
            ],
            'Namecheap Private Email' => [
                'host' => 'mail.privateemail.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Utiliza la dirección completa y la contraseña del buzón de Namecheap Private Email.',
            ],
            'Yahoo' => [
                'host' => 'imap.mail.yahoo.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Genera una contraseña de aplicación desde la seguridad de Yahoo.',
            ],
            'iCloud (Apple Mail)' => [
                'host' => 'imap.mail.me.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Crea una contraseña específica para aplicaciones desde tu Apple ID.',
            ],
            'Zoho Mail' => [
                'host' => 'imappro.zoho.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Con verificación en dos pasos, utiliza una contraseña de aplicación.',
            ],
            'GMX' => [
                'host' => 'imap.gmx.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Habilita previamente el acceso IMAP en GMX.',
            ],
            'Mail.com' => [
                'host' => 'imap.mail.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Habilita previamente el acceso IMAP en Mail.com.',
            ],
            'IONOS by 1&1' => [
                'host' => 'imap.ionos.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Utiliza la contraseña del buzón creado en IONOS.',
            ],
            'Hostinger Mail' => [
                'host' => 'imap.hostinger.com',
                'port' => 993,
                'flags' => '/imap/ssl',
                'message' => 'Utiliza la contraseña del buzón de Hostinger.',
            ],
        ];
    }

    /** @return list<string> */
    public static function selectOptions(): array
    {
        return [...array_keys(self::providers()), 'Otra'];
    }

    public static function isMicrosoftProvider(string $provider, string $host = ''): bool
    {
        $value = strtolower(trim($provider . ' ' . $host));
        foreach ([
            'outlook',
            'office 365',
            'office365',
            'hotmail',
            'live.com',
            'outlook.office365.com',
            'imap-mail.outlook.com',
        ] as $needle) {
            if (str_contains($value, $needle)) {
                return true;
            }
        }
        return false;
    }

    /** @return array{provider:string,host:string,port:int,flags:string} */
    public static function resolve(
        string $provider,
        string $manualName,
        string $manualHost,
        int $manualPort,
        string $manualFlags
    ): array {
        $provider = trim($provider);
        $catalog = self::providers();

        if (self::isMicrosoftProvider($provider, $manualHost)) {
            throw new InvalidArgumentException('Outlook y Office 365 fueron retirados del módulo Buzones. Selecciona otro proveedor.');
        }

        if (isset($catalog[$provider])) {
            return [
                'provider' => $provider,
                'host' => $catalog[$provider]['host'],
                'port' => $catalog[$provider]['port'],
                'flags' => $catalog[$provider]['flags'],
            ];
        }

        if ($provider !== 'Otra') {
            throw new InvalidArgumentException('Selecciona un proveedor válido.');
        }

        $manualName = trim($manualName);
        $manualHost = strtolower(trim($manualHost));
        $manualFlags = trim($manualFlags);

        if ($manualName === '' || $manualHost === '') {
            throw new InvalidArgumentException('Completa el nombre y el host del proveedor manual.');
        }
        if (!filter_var($manualHost, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME)
            && !filter_var($manualHost, FILTER_VALIDATE_IP)) {
            throw new InvalidArgumentException('El host IMAP no es válido.');
        }
        if ($manualPort < 1 || $manualPort > 65535) {
            throw new InvalidArgumentException('El puerto IMAP no es válido.');
        }
        if ($manualFlags === '' || preg_match('/[\r\n{}]/', $manualFlags)) {
            throw new InvalidArgumentException('Los flags IMAP no son válidos.');
        }
        if (self::isMicrosoftProvider($manualName, $manualHost)) {
            throw new InvalidArgumentException('Los servidores de Outlook y Office 365 no están permitidos.');
        }

        return [
            'provider' => $manualName,
            'host' => $manualHost,
            'port' => $manualPort,
            'flags' => $manualFlags,
        ];
    }
}
