<?php

declare(strict_types=1);

namespace Dealerdirect\Agreements\Mailers;

use Dealerdirect\Agreements\DataObjects\SalesAgreement;
use Dealerdirect\Agreements\Enums\Locale;
use Dealerdirect\Agreements\Utils\GeneralUtils;
use DealerDirect\Generic\Category\EmailType;
use DealerDirect\Generic\Category\Site;
use DealerDirect\Generic\Category\VehicleType;
use DealerDirect\Sdk\Facade\Email as EmailClient;
use Dealerdirect\Sdk\Model\Email\Attachment;
use Dealerdirect\Sdk\Model\Email\Email;
use Dealerdirect\Sdk\Model\Email\Recipient;
use Dealerdirect\Sdk\Model\Email\SubstitutionKeys;
use Dealerdirect\Sdk\Model\Email\Substitutions;

/**
 * @property SalesAgreement $data
 */
final class SalesAgreementMailer extends Mailer
{
    /**
     * @inheritDoc
     */
    public function getRecipients(): array
    {
        return array_map(
            fn (string $email) => new Recipient($email, $this->data->consumer->getName()),
            $this->data->consumer->getValidEmails()
        );
    }

    /**
     * @inheritDoc
     */
    public function getCc(): array
    {
        return [];
    }

    /**
     * @inheritDoc
     */
    public function getBcc(): array
    {
        $bcc = [];
        if (GeneralUtils::isMotor($this->data->vehicleType)) {
            $bcc[] = new Recipient('kerim@dealerdirect.nl', 'Kerim Gilbers');
        }

        return $bcc;
    }

    /**
     * @param array<string,string> $domains
     */
    public static function create(
        EmailClient $client,
        SalesAgreement $data,
        string $agreementPdf,
        array $domains,
        string $encryptionKey
    ): self {
        return new self($client, self::getEmail($data, $agreementPdf, $domains, $encryptionKey), $data);
    }

    /**
     * @param array<string,string> $domains
     */
    public static function getEmail(
        SalesAgreement $data,
        string $agreementPdf,
        array $domains,
        string $encryptionKey
    ): Email {
        return new Email(
            $data->locale->value,
            Site::REF_CAR_MARKTPLAATS_NL === $data->siteReference ? 'marktplaats' : $data->vehicleType,
            EmailType::SALE_AGREEMENT,
            self::getSubstitutions($data, $domains, $encryptionKey),
            self::getAttachments($agreementPdf, $data)
        );
    }

    /**
     * @return Attachment[]
     */
    private static function getAttachments(string $agreementPdf, SalesAgreement $data): array
    {
        $pdfName = GeneralUtils::getTranslator($data)->get('sales_agreement.pdf', ['id' => $data->lotId]);
        $attachments = [
            new Attachment($agreementPdf, 'application/pdf', $pdfName),
        ];

        $vehicleType = $data->vehicleType;
        if (Locale::NL_NL === $data->locale && VehicleType::BICYCLE !== $vehicleType) {
            $filesPath = dirname(__DIR__, 2) . '/resources/files';

            $file = "{$filesPath}/Controlelijst_IWVMAA.pdf";
            if (VehicleType::MOTOR === $vehicleType) {
                $file = "{$filesPath}/SD-00414_Kentekendocumenten_Overdracht.pdf";
            } elseif (VehicleType::SCOOTER === $vehicleType) {
                $file = "{$filesPath}/SD-00414_Kentekendocumenten_Overdracht_ScooterNL.pdf";
            } elseif (Site::REF_CAR_MARKTPLAATS_NL === $data->siteReference) {
                $file = "{$filesPath}/MP_000001_overdracht.pdf";
            }

            $attachments[] = new Attachment(file_get_contents($file), 'application/pdf', 'Documenten_Overdracht.pdf');
        }

        return $attachments;
    }

    /**
     * @param array<string,string> $domains
     */
    private static function getSubstitutions(SalesAgreement $data, array $domains, string $encryptionKey): Substitutions
    {
        $validConsumerEmails = $data->consumer->getValidEmails();
        $validCompanyEmails = $data->company->getValidEmails();
        $substitutions = [
            SubstitutionKeys::CONSUMER_ADDRESS => $data->consumer->getAddress(),
            SubstitutionKeys::CONSUMER_EMAIL => reset($validConsumerEmails),
            SubstitutionKeys::CONSUMER_PHONE => GeneralUtils::combinePhoneNumbers(
                $data->consumer->phoneNumbers[0] ?? '',
                $data->consumer->phoneNumbers[1] ?? '',
                $data->consumer->country,
            ),

            SubstitutionKeys::DEALER_ADDRESS => $data->company->getAddress(),
            SubstitutionKeys::DEALER_EMAIL => reset($validCompanyEmails),
            SubstitutionKeys::DEALER_NAME => $data->company->name,
            SubstitutionKeys::DEALER_PHONE => GeneralUtils::combinePhoneNumbers(
                $data->company->phoneNumbers[0] ?? '',
                $data->company->phoneNumbers[1] ?? '',
                $data->company->country,
            ),

            SubstitutionKeys::FIRST_NAME => $data->consumer->firstName,
            SubstitutionKeys::LAST_NAME => $data->consumer->lastName,
            SubstitutionKeys::LOT_NUMBER => $data->lotId,
            SubstitutionKeys::VEHICLE_MAKE => $data->vehicle->brand,
            SubstitutionKeys::VEHICLE_MODEL => $data->vehicle->model,

            SubstitutionKeys::URL => self::getDeliveryUrl($data, $domains, $encryptionKey),
        ];

        $reference = $data->siteReference;
        if (Site::REF_CAR_MARKTPLAATS_NL === $reference) {
            $agentName = $data->salesAgent->name;
            $substitutions[SubstitutionKeys::AGENT_PHONE] = GeneralUtils::getAgentPhoneByReference($reference);
            $substitutions[SubstitutionKeys::AGENT_NAME] = ('-' === $agentName || empty($agentName))
                ? 'Het Marktplaats team'
                : $agentName;
        } elseif (GeneralUtils::isMotor($data->vehicleType)) {
            $substitutions[SubstitutionKeys::AGENT_PHONE] = GeneralUtils::getAgentPhoneByReference($reference);
            if (Locale::DE_DE === $data->locale) {
                $substitutions[SubstitutionKeys::VEHICLE_CONSUMER_PRICE] = GeneralUtils::getConsumerPrice(
                    $data->salesPrice,
                    $data->salesFee
                );
                $substitutions[SubstitutionKeys::SALUTATION] = GeneralUtils::getSalutationByGender(
                    $data->locale->value,
                    (int) $data->consumer->salutation,
                );
            }
        }

        return new Substitutions($substitutions);
    }

    /**
     * @param array<string,string> $domains
     */
    private static function getDeliveryUrl(SalesAgreement $data, array $domains, string $encryptionKey): string
    {
        $reference = $data->siteReference;
        $domain = self::getDomainByReference($reference, $domains);
        $encryptedId = GeneralUtils::encrypt($encryptionKey, $data->deliverId);

        $endpoint = "/afhandeling-levering/{$encryptedId}";
        if (in_array($reference, [Site::REF_CAR_DE, Site::REF_MOTO_DE], true)) {
            $endpoint = "/lieferung/{$encryptedId}";
        } elseif (Site::REF_CAR_MARKTPLAATS_NL === $reference) {
            $endpoint = "/#/afhandeling-levering?token={$encryptedId}";
        }

        return sprintf('%s%s', rtrim($domain, '/'), $endpoint);
    }

    /**
     * @param array<string,string> $domains
     */
    private static function getDomainByReference(int $reference, array $domains): string
    {
        $url = parse_url(match ($reference) {
            Site::REF_CAR_NL => $domains['carNl'],
            Site::REF_CAR_BE_NL => $domains['carBe'],
            Site::REF_CAR_DE => $domains['carDe'],
            Site::REF_MOTO_NL => $domains['motorNl'],
            Site::REF_MOTO_BE => $domains['motorBe'],
            Site::REF_MOTO_DE => $domains['motorDe'],
            Site::REF_SCOOTER_NL => $domains['scooterNl'],
            Site::REF_BICYCLE_NL => $domains['bicycleNl'],
            Site::REF_CAR_MARKTPLAATS_NL => $domains['marktplaatsNl'],
            default => throw new \InvalidArgumentException("Invalid site reference: $reference"),
        });

        return rtrim(
            sprintf(
                '%s://%s%s%s%s',
                $url['scheme'] ?? 'https',
                $url['host'] ?? '',
                isset($url['port']) ? ":{$url['port']}" : '',
                $url['path'] ?? '',
                isset($url['query']) ? "?{$url['query']}" : '',
            ),
            '/'
        );
    }
}
