<?php

declare(strict_types=1);

namespace Dealerdirect\Agreements\Factories;

use Dealerdirect\Agreements\DataObjects;
use Dealerdirect\Agreements\Exceptions\EmptyConsumerDomainsException;
use Dealerdirect\Agreements\Exceptions\EmptyEncryptionKeyException;
use Dealerdirect\Agreements\Exceptions\InvalidSiteReferenceException;
use Dealerdirect\Agreements\Exceptions\SalesAgreementNotStoredException;
use Dealerdirect\Agreements\Mailers\SalesAgreementMailer;
use Dealerdirect\Agreements\Pdf\Generator;
use Dealerdirect\Agreements\Pdf\Templates;
use Dealerdirect\Agreements\Utils\GeneralUtils;
use DealerDirect\Generic\Category\Site;
use DealerDirect\Sdk\Facade\Email;
use Illuminate\Contracts\Filesystem\Filesystem;

final class SalesAgreementFactory implements Factory
{
    public function __construct(
        public readonly DataObjects\SalesAgreement $data,
        private Filesystem $storage,
        private Generator $generator,
    ) {
    }

    public function exists(): bool
    {
        return $this->storage->exists(
            $this->getStorageName()
        );
    }

    public function store(string $pdfContent): void
    {
        $storageName = $this->getStorageName();

        if (!$this->storage->put($storageName, $pdfContent)) {
            throw new SalesAgreementNotStoredException(
                $this->data->lotId,
                $this->data->company->id,
                $this->data->siteReference,
                $storageName
            );
        }
    }

    /**
     * @param array<string,string> $domains
     */
    public function send(Email $emailClient, ?array $domains = null, ?string $encryptionKey = null): void
    {
        if (empty($domains)) {
            throw new EmptyConsumerDomainsException();
        }

        if (empty($encryptionKey)) {
            throw new EmptyEncryptionKeyException();
        }

        SalesAgreementMailer::create(
            $emailClient,
            $this->data,
            $this->show(),
            $domains,
            $encryptionKey
        )->send();
    }

    public function create(): void
    {
        if ($this->exists()) {
            return;
        }

        $this->store($this->generator->generate());
    }

    public function show(): string
    {
        if (!$this->exists()) {
            $this->create();
        }

        return $this->storage->get($this->getStorageName());
    }

    public function delete(): void
    {
        if (!$this->exists()) {
            return;
        }

        $this->storage->delete(
            $this->getStorageName()
        );
    }

    public function getStorageName(): string
    {
        return sprintf('verkoopovereenkomsten/%s.pdf', sha1(
            $this->data->company->id
            . $this->data->soldDate->format('Y-m-d H:i:s')
            . $this->data->deliverId
            . ($this->data->vehicle->brand ?? 'unknown-make')
        ));
    }

    public static function getSalesAgreementTemplate(
        DataObjects\SalesAgreement $data
    ): Templates\SalesAgreement {
        $translator = GeneralUtils::getTranslator($data);

        return match ($data->siteReference) {
            Site::REF_CAR_NL,
            Site::REF_CAR_BE_NL => new Templates\CarSalesAgreement($data->locale, $data, $translator),
            Site::REF_CAR_MARKTPLAATS_NL => new Templates\MarktplaatsSalesAgreement($data->locale, $data, $translator),
            Site::REF_MOTO_NL,
            Site::REF_MOTO_BE,
            Site::REF_MOTO_DE,
            Site::REF_SCOOTER_NL => new Templates\MotorbikeSalesAgreement($data->locale, $data, $translator),
            Site::REF_BICYCLE_NL => new Templates\BicycleSalesAgreement($data->locale, $data, $translator),

            default => throw new InvalidSiteReferenceException($data->siteReference),
        };
    }
}
