<?php

declare(strict_types=1);

namespace Dealerdirect\Agreements\Pdf\Templates;

use Dealerdirect\Agreements\DataObjects\DataObject;
use Dealerdirect\Agreements\Enums\Locale;
use Dealerdirect\Agreements\Utils\GeneralUtils;
use Dealerdirect\Agreements\Utils\Translator;
use DealerDirect\Generic\Category\Site;

/**
 * @property \Dealerdirect\Agreements\DataObjects\SalesAgreement $data
 */
abstract class SalesAgreement extends AbstractTemplate
{
    public function __construct(
        protected Locale $locale,
        protected DataObject|\Dealerdirect\Agreements\DataObjects\SalesAgreement $data,
        protected Translator $translator,
        ?string $resourcesFolder = null
    ) {
        parent::__construct($locale, $data, $translator, $resourcesFolder);
    }

    public function getTemplate(): string
    {
        return 'sales-agreement.php';
    }

    /**
     * @return string[] The parties to be rendered
     */
    public function getParties(): array
    {
        $name = $this->data->consumer->name;
        if ($this->data->consumer->companyNameSeller) {
            $name .= " ({$this->data->consumer->companyNameSeller})";
        }

        return [
            $this->translate('sales_agreement.first_party', $this->allToUpperCaseExcept([
                'name' => $name,
                'street_name' => $this->data->consumer->streetName,
                'house_number' => $this->data->consumer->houseNumber,
                'zip_code' => $this->data->consumer->zipCode,
                'city' => $this->data->consumer->city,
                'country' => $this->translate("general.country.{$this->data->consumer->country}"),
                'phone' => GeneralUtils::combinePhoneNumbers(
                    $this->data->consumer->phoneNumbers[0] ?? '',
                    $this->data->consumer->phoneNumbers[1] ?? '',
                    $this->data->consumer->country,
                ),
                'email' => GeneralUtils::combineValues(' / ', $this->data->consumer->getValidEmails()),
            ], ['email', 'phone'])),

            $this->translate('sales_agreement.second_party', $this->allToUpperCaseExcept([
                'name' => $this->data->company->name,
                'street_name' => $this->data->company->streetName,
                'house_number' => $this->data->company->houseNumber,
                'zip_code' => $this->data->company->zipCode,
                'city' => $this->data->company->city,
                'country' => $this->translate("general.country.{$this->data->company->country}"),
                'phone' => GeneralUtils::combinePhoneNumbers(
                    $this->data->company->phoneNumbers[0] ?? '',
                    $this->data->company->phoneNumbers[1] ?? '',
                    $this->data->company->country,
                ),
                'email' => GeneralUtils::combineValues(' / ', $this->data->company->getValidEmails()),
            ], ['email', 'phone'])),
        ];
    }

    public function getLogo(): string
    {
        $file = match ($this->data->siteReference) {
            Site::REF_BICYCLE_NL => 'logo_bicycle.png',
            Site::REF_CAR_BE_NL,
            Site::REF_CAR_NL => 'logo_car.svg',
            Site::REF_CAR_MARKTPLAATS_NL => 'logo_marktplaats.svg',
            Site::REF_MOTO_BE,
            Site::REF_MOTO_NL => 'logo_motorbike.svg',
            Site::REF_MOTO_DE => 'logo_motorbike_de.png',
            Site::REF_SCOOTER_NL => 'logo_scooter.svg',

            default => throw new \InvalidArgumentException(
                "No logo found for site reference {$this->data->siteReference}"
            ),
        };

        return $this->encodedImage($file);
    }

    public function getStamp(): string
    {
        //no stamp needed for marktplaats template
        $file = match ($this->data->siteReference) {
            Site::REF_BICYCLE_NL => 'stamp_bicycle.png',
            Site::REF_CAR_BE_NL,
            Site::REF_CAR_NL => 'stamp_car.png',
            Site::REF_MOTO_BE,
            Site::REF_MOTO_NL,
            Site::REF_MOTO_DE => 'stamp_motorbike.png',
            Site::REF_SCOOTER_NL => 'stamp_scooter.png',

            default => throw new \InvalidArgumentException(
                "No stamp found for site reference {$this->data->siteReference}"
            ),
        };

        return $this->encodedImage($file);
    }

    private function encodedImage(string $file): string
    {
        $path = "{$this->resourcesFolder}/img/{$file}";
        $type = pathinfo($path, PATHINFO_EXTENSION);

        return "data:image/{$type};base64," . base64_encode(
            file_get_contents($path)
        );
    }

    /**
     * @param array<string,string> $data
     * @param array<int,string>    $exceptions
     *
     * @return array<string,string>
     */
    private function allToUpperCaseExcept(array $data, array $exceptions): array
    {
        foreach ($data as $key => &$value) {
            if (!in_array($key, $exceptions, true)) {
                $value = mb_strtoupper($value, 'UTF-8');
            }
        }

        return $data;
    }

    /**
     * @return array<string,string|array<int,array<string,string>>> The agreements to be rendered
     */
    abstract public function getAgreements(): array;

    /**
     * @return array<int,array<string,string>> The vehicle values to be rendered
     */
    abstract public function getVehicleValues(): array;

    /**
     * @return array<string,string> Whether to show the consideration
     */
    abstract public function getConsideration(): ?array;

    /**
     * @return array<string,string> Whether to show the mediation
     */
    abstract public function getMediation(): ?array;
}
