<?php

declare(strict_types=1);

namespace App\Http\Controllers;

use App\Models\EmailDomain;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Http\Response;

/**
 * Autoconfig Controller for Mozilla Thunderbird and other clients
 *
 * Implements the Mozilla Autoconfig protocol for automatic email configuration.
 * Also provides mobile configuration profiles for iOS devices.
 */
class AutoconfigController extends Controller
{
    /**
     * Handle autoconfig request (Mozilla Thunderbird style)
     * URL: /mail/config-v1.1.xml?emailaddress=user@example.com
     * URL: /.well-known/autoconfig/mail/config-v1.1.xml?emailaddress=user@example.com
     */
    public function config(Request $request): Response
    {
        $email = $this->normalizeEmail($request->query('emailaddress'));

        if (! $email) {
            return response('Email parameter required', 400);
        }

        $parts = explode('@', $email);
        if (count($parts) !== 2) {
            return response('Invalid email address', 400);
        }

        $domain = $parts[1];

        // Check if domain is managed
        $emailDomain = EmailDomain::whereHas('domain', function ($query) use ($domain) {
            $query->where('domain_name', $domain);
        })->where('is_active', true)->first();

        if (! $emailDomain) {
            return response('Domain not configured', 404);
        }

        $mailServer = $this->getMailServer($emailDomain);
        $displayName = Setting::get('webmail_product_name', 'Jabali Mail');

        return $this->autoconfigResponse($domain, $mailServer, $displayName);
    }

    /**
     * Handle autoconfig for specific domain
     * URL: /autoconfig/domain.com/config-v1.1.xml
     */
    public function configForDomain(Request $request, string $domain): Response
    {
        if (! $this->isValidDomain($domain)) {
            return response('Invalid domain', 400);
        }

        $emailDomain = EmailDomain::whereHas('domain', function ($query) use ($domain) {
            $query->where('domain_name', $domain);
        })->where('is_active', true)->first();

        if (! $emailDomain) {
            return response('Domain not configured', 404);
        }

        $mailServer = $this->getMailServer($emailDomain);
        $displayName = Setting::get('webmail_product_name', 'Jabali Mail');

        return $this->autoconfigResponse($domain, $mailServer, $displayName);
    }

    /**
     * Generate iOS/macOS mobile configuration profile
     * URL: /mail/profile/{domain}
     */
    public function mobileProfile(Request $request, string $domain): Response
    {
        if (! $this->isValidDomain($domain)) {
            return response('Invalid domain', 400);
        }

        $email = $this->normalizeEmail($request->query('email'));

        if (! $email) {
            return response('Email parameter required', 400);
        }

        $emailDomainName = substr(strrchr($email, '@') ?: '', 1);
        if ($emailDomainName !== $domain) {
            return response('Email does not match domain', 400);
        }

        $emailDomain = EmailDomain::whereHas('domain', function ($query) use ($domain) {
            $query->where('domain_name', $domain);
        })->where('is_active', true)->first();

        if (! $emailDomain) {
            return response('Domain not configured', 404);
        }

        $mailServer = $this->getMailServer($emailDomain);
        $displayName = Setting::get('webmail_product_name', 'Jabali Mail');
        $escapedDomain = $this->escapeXml($domain);
        $escapedEmail = $this->escapeXml($email);
        $escapedMailServer = $this->escapeXml($mailServer);
        $escapedDisplayName = $this->escapeXml($displayName);
        $uuid = $this->generateUuid();
        $payloadUuid = $this->generateUuid();

        $profile = <<<MOBILECONFIG
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>PayloadContent</key>
    <array>
        <dict>
            <key>EmailAccountDescription</key>
            <string>{$escapedDomain} Email</string>
            <key>EmailAccountName</key>
            <string>{$escapedDisplayName}</string>
            <key>EmailAccountType</key>
            <string>EmailTypeIMAP</string>
            <key>EmailAddress</key>
            <string>{$escapedEmail}</string>
            <key>IncomingMailServerAuthentication</key>
            <string>EmailAuthPassword</string>
            <key>IncomingMailServerHostName</key>
            <string>{$escapedMailServer}</string>
            <key>IncomingMailServerPortNumber</key>
            <integer>993</integer>
            <key>IncomingMailServerUseSSL</key>
            <true/>
            <key>IncomingMailServerUsername</key>
            <string>{$escapedEmail}</string>
            <key>OutgoingMailServerAuthentication</key>
            <string>EmailAuthPassword</string>
            <key>OutgoingMailServerHostName</key>
            <string>{$escapedMailServer}</string>
            <key>OutgoingMailServerPortNumber</key>
            <integer>587</integer>
            <key>OutgoingMailServerUseSSL</key>
            <true/>
            <key>OutgoingMailServerUsername</key>
            <string>{$escapedEmail}</string>
            <key>OutgoingPasswordSameAsIncomingPassword</key>
            <true/>
            <key>PayloadDescription</key>
            <string>Email account configuration for {$escapedDomain}</string>
            <key>PayloadDisplayName</key>
            <string>{$escapedDomain} Email</string>
            <key>PayloadIdentifier</key>
            <string>com.jabali.email.{$escapedDomain}</string>
            <key>PayloadType</key>
            <string>com.apple.mail.managed</string>
            <key>PayloadUUID</key>
            <string>{$payloadUuid}</string>
            <key>PayloadVersion</key>
            <integer>1</integer>
            <key>PreventAppSheet</key>
            <false/>
            <key>PreventMove</key>
            <false/>
            <key>SMIMEEnabled</key>
            <false/>
        </dict>
    </array>
    <key>PayloadDescription</key>
    <string>Email configuration profile for {$escapedDomain}</string>
    <key>PayloadDisplayName</key>
    <string>{$escapedDisplayName} - {$escapedDomain}</string>
    <key>PayloadIdentifier</key>
    <string>com.jabali.mailconfig.{$escapedDomain}</string>
    <key>PayloadOrganization</key>
    <string>{$escapedDisplayName}</string>
    <key>PayloadRemovalDisallowed</key>
    <false/>
    <key>PayloadType</key>
    <string>Configuration</string>
    <key>PayloadUUID</key>
    <string>{$uuid}</string>
    <key>PayloadVersion</key>
    <integer>1</integer>
</dict>
</plist>
MOBILECONFIG;

        return response($profile, 200)
            ->header('Content-Type', 'application/x-apple-aspen-config')
            ->header('Content-Disposition', 'attachment; filename="email-config.mobileconfig"');
    }

    /**
     * Get mail server hostname
     */
    private function getMailServer(EmailDomain $emailDomain): string
    {
        $hostname = Setting::get('mail_hostname');

        if ($hostname) {
            return $hostname;
        }

        return 'mail.'.$emailDomain->domain->domain_name;
    }

    /**
     * Generate autoconfig XML response
     */
    private function autoconfigResponse(string $domain, string $mailServer, string $displayName): Response
    {
        $escapedDomain = $this->escapeXml($domain);
        $escapedMailServer = $this->escapeXml($mailServer);
        $escapedDisplayName = $this->escapeXml($displayName);

        $xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<clientConfig version="1.1">
    <emailProvider id="{$escapedDomain}">
        <domain>{$escapedDomain}</domain>
        <displayName>{$escapedDisplayName}</displayName>
        <displayShortName>{$escapedDisplayName}</displayShortName>
        <incomingServer type="imap">
            <hostname>{$escapedMailServer}</hostname>
            <port>993</port>
            <socketType>SSL</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </incomingServer>
        <incomingServer type="pop3">
            <hostname>{$escapedMailServer}</hostname>
            <port>995</port>
            <socketType>SSL</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </incomingServer>
        <outgoingServer type="smtp">
            <hostname>{$escapedMailServer}</hostname>
            <port>587</port>
            <socketType>STARTTLS</socketType>
            <authentication>password-cleartext</authentication>
            <username>%EMAILADDRESS%</username>
        </outgoingServer>
        <documentation url="https://{$escapedDomain}/webmail">
            <descr lang="en">Webmail access</descr>
        </documentation>
    </emailProvider>
</clientConfig>
XML;

        return response($xml, 200)
            ->header('Content-Type', 'application/xml; charset=utf-8');
    }

    private function normalizeEmail(?string $email): ?string
    {
        if ($email === null) {
            return null;
        }

        $email = trim($email);

        if ($email === '' || ! filter_var($email, FILTER_VALIDATE_EMAIL)) {
            return null;
        }

        return $email;
    }

    private function isValidDomain(string $domain): bool
    {
        return filter_var($domain, FILTER_VALIDATE_DOMAIN, FILTER_FLAG_HOSTNAME) !== false;
    }

    private function escapeXml(string $value): string
    {
        return htmlspecialchars($value, ENT_XML1 | ENT_QUOTES, 'UTF-8');
    }

    /**
     * Generate UUID v4
     */
    private function generateUuid(): string
    {
        return sprintf(
            '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
            mt_rand(0, 0xFFFF),
            mt_rand(0, 0xFFFF),
            mt_rand(0, 0xFFFF),
            mt_rand(0, 0x0FFF) | 0x4000,
            mt_rand(0, 0x3FFF) | 0x8000,
            mt_rand(0, 0xFFFF),
            mt_rand(0, 0xFFFF),
            mt_rand(0, 0xFFFF)
        );
    }
}
