<?php

namespace App\Service;

use Symfony\Component\DependencyInjection\Attribute\Autowire;
use Symfony\Contracts\HttpClient\HttpClientInterface;

/**
 * @codeCoverageIgnore
 */
class AwsSesService
{
    public function __construct(
        private HttpClientInterface $httpClient,
        #[Autowire(env: 'AWS_PK')] private string $accessKey,
        #[Autowire(env: 'AWS_SECRET')] private string $secretKey,
        #[Autowire(env: 'AWS_REGION')] private string $region,
    ) {
    }

    /**
     * Verifier si un domaine est verifie dans SES.
     */
    public function isDomainVerified(string $domain): ?string
    {
        $xml = $this->call('GetIdentityVerificationAttributes', ['Identities.member.1' => $domain]);

        if (str_contains($xml, '<VerificationStatus>Success</VerificationStatus>')) {
            return 'Success';
        }
        if (str_contains($xml, '<VerificationStatus>Pending</VerificationStatus>')) {
            return 'Pending';
        }

        return null;
    }

    /**
     * Verifier le statut DKIM d'un domaine.
     *
     * @return array{enabled: bool, verified: bool, tokens: list<string>}
     */
    public function getDkimStatus(string $domain): array
    {
        $xml = $this->call('GetIdentityDkimAttributes', ['Identities.member.1' => $domain]);

        $enabled = str_contains($xml, '<DkimEnabled>true</DkimEnabled>');
        $verified = str_contains($xml, '<DkimVerificationStatus>Success</DkimVerificationStatus>');

        $tokens = [];
        if (preg_match_all('/<member>([^<]+)<\/member>/', $xml, $matches)) {
            $tokens = $matches[1];
        }

        return ['enabled' => $enabled, 'verified' => $verified, 'tokens' => $tokens];
    }

    /**
     * Verifier le statut des notifications bounce.
     *
     * @return array{bounce_topic: string|null, complaint_topic: string|null, forwarding: bool}
     */
    public function getNotificationStatus(string $domain): array
    {
        $xml = $this->call('GetIdentityNotificationAttributes', ['Identities.member.1' => $domain]);

        $bounceTopic = null;
        if (preg_match('/<BounceTopic>([^<]+)<\/BounceTopic>/', $xml, $m)) {
            $bounceTopic = $m[1];
        }

        $complaintTopic = null;
        if (preg_match('/<ComplaintTopic>([^<]+)<\/ComplaintTopic>/', $xml, $m)) {
            $complaintTopic = $m[1];
        }

        $forwarding = str_contains($xml, '<ForwardingEnabled>true</ForwardingEnabled>');

        return ['bounce_topic' => $bounceTopic, 'complaint_topic' => $complaintTopic, 'forwarding' => $forwarding];
    }

    /**
     * Lister toutes les identites verifiees.
     *
     * @return list<string>
     */
    public function listVerifiedIdentities(): array
    {
        $xml = $this->call('ListIdentities', ['IdentityType' => 'Domain']);

        $identities = [];
        if (preg_match_all('/<member>([^<]+)<\/member>/', $xml, $matches)) {
            $identities = $matches[1];
        }

        return $identities;
    }

    /**
     * Recuperer la configuration MAIL FROM d'un domaine.
     *
     * @return array{mail_from_domain: string|null, mail_from_status: string|null, mx_expected: string|null, txt_expected: string|null}
     */
    public function getMailFromStatus(string $domain): array
    {
        $xml = $this->call('GetIdentityMailFromDomainAttributes', ['Identities.member.1' => $domain]);

        $mailFromDomain = null;
        if (preg_match('/<MailFromDomain>([^<]+)<\/MailFromDomain>/', $xml, $m)) {
            $mailFromDomain = $m[1];
        }

        $status = null;
        if (preg_match('/<MailFromDomainStatus>([^<]+)<\/MailFromDomainStatus>/', $xml, $m)) {
            $status = $m[1];
        }

        $mxExpected = null !== $mailFromDomain ? 'feedback-smtp.'.$this->region.'.amazonses.com' : null;
        $txtExpected = null !== $mailFromDomain ? 'v=spf1 include:amazonses.com ~all' : null;

        return [
            'mail_from_domain' => $mailFromDomain,
            'mail_from_status' => $status,
            'mx_expected' => $mxExpected,
            'txt_expected' => $txtExpected,
        ];
    }

    /**
     * Verifier si l'API est fonctionnelle.
     */
    public function isAvailable(): bool
    {
        if ('' === $this->accessKey || '' === $this->secretKey) {
            return false;
        }

        try {
            $this->call('GetSendQuota');

            return true;
        } catch (\Throwable) {
            return false;
        }
    }

    /**
     * @param array<string, string> $params
     */
    private function call(string $action, array $params = []): string
    {
        $host = 'email.'.$this->region.'.amazonaws.com';
        $now = new \DateTimeImmutable('now', new \DateTimeZone('UTC'));
        $dateStamp = $now->format('Ymd');
        $amzDate = $now->format('Ymd\THis\Z');

        $params['Action'] = $action;
        ksort($params);
        $queryString = http_build_query($params);

        $canonicalRequest = "GET\n/\n$queryString\nhost:$host\nx-amz-date:$amzDate\n\nhost;x-amz-date\ne3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
        $credentialScope = "$dateStamp/{$this->region}/ses/aws4_request";
        $stringToSign = "AWS4-HMAC-SHA256\n$amzDate\n$credentialScope\n".hash('sha256', $canonicalRequest);

        $kDate = hash_hmac('sha256', $dateStamp, 'AWS4'.$this->secretKey, true);
        $kRegion = hash_hmac('sha256', $this->region, $kDate, true);
        $kService = hash_hmac('sha256', 'ses', $kRegion, true);
        $kSigning = hash_hmac('sha256', 'aws4_request', $kService, true);
        $signature = hash_hmac('sha256', $stringToSign, $kSigning);

        $authorization = "AWS4-HMAC-SHA256 Credential={$this->accessKey}/$credentialScope, SignedHeaders=host;x-amz-date, Signature=$signature";

        $response = $this->httpClient->request('GET', "https://$host/?$queryString", [
            'headers' => [
                'x-amz-date' => $amzDate,
                'Authorization' => $authorization,
            ],
        ]);

        return $response->getContent(false);
    }
}
