<?php

declare(strict_types=1);

namespace Dealerdirect\Agreements\Factories;

use Cloudinary\Cloudinary;
use Dealerdirect\Agreements\DataObjects;
use Dealerdirect\Agreements\Enums\DealerdirectLanguage;
use Dealerdirect\Agreements\Exceptions\PurchaseAgreementNotStoredException;
use Dealerdirect\Agreements\Mailers\PurchaseAgreementMailer;
use Dealerdirect\Agreements\Pdf\Generator;
use Dealerdirect\Agreements\Pdf\Templates;
use Dealerdirect\Agreements\Utils\GeneralUtils;
use DealerDirect\Sdk\Facade\Email;
use Illuminate\Contracts\Filesystem\Filesystem;

final class PurchaseAgreementFactory implements Factory
{
    public const REQUESTED_BY = 'dealerdirect-agreements';

    public const STORAGE_NAME_V2_CUT_OFF_DATE = '2025-09-22';

    public function __construct(
        public readonly DataObjects\PurchaseAgreement $data,
        private Filesystem $storage,
        private Generator $generator,
        private ?DealerdirectLanguage $language = null,
    ) {
        $this->language ??= $this->data->locale->toDealerdirectLanguage();

        // Check if storage has folder, if not create it
        if (!in_array('purchase-agreements', $this->storage->directories(), true)) {
            $this->storage->makeDirectory('purchase-agreements');
        }
    }

    public function setLanguage(DealerdirectLanguage $language): void
    {
        $this->language = $language;
    }

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

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

        $currentLanguage = $this->language;

        foreach (DealerdirectLanguage::cases() as $language) {
            $this->setLanguage($language);

            $pdfContent = $this->generator->generate();

            $this->store($pdfContent);
        }

        $this->language = $currentLanguage;
    }

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

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

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

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

    public function delete(): void
    {
        $currentLanguage = $this->language;

        foreach (DealerdirectLanguage::cases() as $language) {
            $this->setLanguage($language);

            $storageName = $this->getStorageName();
            if ($this->storage->exists($storageName)) {
                $this->storage->delete($storageName);
            }
        }

        $this->language = $currentLanguage;
    }

    /**
     * @param array<string,string> $domains
     */
    public function send(Email $emailClient, ?array $domains = null, ?string $encryptionKey = null): void
    {
        PurchaseAgreementMailer::create($emailClient, $this->data, $this->show())->send();
    }

    public function getStorageName(): string
    {
        if ($this->data->soldDate > new \DateTime(self::STORAGE_NAME_V2_CUT_OFF_DATE)) {
            return sprintf('purchase-agreements/v2-%s.pdf', sha1(
                $this->data->siteReference
                . $this->data->deliverId
                . $this->language->value
            ));
        }

        return sprintf('purchase-agreements/%s.pdf', sha1(
            $this->data->company->id
            . $this->data->lotId
            . $this->data->vehicleType
            . $this->language->value
        ));
    }

    public static function getPurchaseAgreementTemplate(
        DataObjects\PurchaseAgreement $data,
        Cloudinary $cloudinary
    ): Templates\PurchaseAgreement {
        $translator = GeneralUtils::getTranslator($data);

        $purchaseAgreement = new Templates\PurchaseAgreement($data->locale, $data, $translator);
        $purchaseAgreement->setCloudinary($cloudinary);

        return $purchaseAgreement;
    }
}
