<?php

namespace Dealerdirect\Agreements\Utils;

use DateTime;
use Dealerdirect\Agreements\DataObjects;
use DealerDirect\Generic\Category\Gender;
use DealerDirect\Generic\Category\Locale;
use DealerDirect\Generic\Category\Site;
use DealerDirect\Generic\Category\VehicleType;
use Dealerdirect\PhoneNumber\Enum\CountryCode;
use Dealerdirect\PhoneNumber\PhoneNumber;
use ParagonIE\Paseto\Keys\Version4\SymmetricKey;
use ParagonIE\Paseto\Protocol\Version4;

class GeneralUtils
{
    /**
     * Sanitizes phone numbers, with country prefix.
     *
     * @param  integer $countryId
     * @param  string  $phone
     * @return string
     */
    public static function sanitizePhoneNumber(int $countryId, string $phone): string
    {
        if (!empty($phone)) {
            try {
                CountryCode::assertExists($countryId);
                $phone = PhoneNumber::from($countryId, $phone);
            } catch (\InvalidArgumentException $exception) {
                //Fail silence
            }
        }

        return $phone;
    }

    /**
     * @param string|null $phone1
     * @param string|null $phone2
     * @param int|null    $countryId
     *
     * @return string
     */
    public static function combinePhoneNumbers($phone1, $phone2, $countryId = null): string
    {
        if (null !== $countryId) {
            $phone1 = self::sanitizePhoneNumber($countryId, $phone1);
            $phone2 = self::sanitizePhoneNumber($countryId, $phone2);
        }

        return self::combineValues(' / ', array_filter([$phone1, $phone2]));
    }

    /**
     * @param array<int|string,mixed> $values
     */
    public static function combineValues(string $separator, array $values): string
    {
        $values = array_unique(array_filter($values));

        return implode($separator, $values);
    }

    /**
     * @param boolean $value
     * @param string  $locale
     *
     * @return string
     */
    public static function translateYesNo($value, $locale): string
    {
        return match ($locale) {
            Locale::NL_NL,
            Locale::NL_BE => $value ? 'ja' : 'nee',
            Locale::FR_BE => $value ? 'oui' : 'non',
            Locale::DE_DE => $value ? 'ja' : 'nein',
            default => "{$value}",
        };
    }

    /**
     * Checks if vehicleType is Motor
     *
     * @param  string  $vehicleType
     * @return boolean
     */
    public static function isMotor(string $vehicleType): bool
    {
        return in_array($vehicleType, [VehicleType::MOTOR, VehicleType::SCOOTER]);
    }

    /**
     * Checks if vehicleType is Car.
     *
     * @param  string  $vehicleType
     * @return boolean
     */
    public static function isCar(string $vehicleType): bool
    {
        return in_array($vehicleType, [
            VehicleType::CAR, VehicleType::RECREATION, VehicleType::CARAVAN, VehicleType::CAMPER,
        ]);
    }

    /**
     * Checks if vehicleType is Bicycle.
     *
     * @param  string  $vehicleType
     * @return boolean
     */
    public static function isBicycle(string $vehicleType): bool
    {
        return VehicleType::BICYCLE === $vehicleType;
    }

    /**
     * Gets the locale by company pri_lang(db field)
     *
     * @param  integer $lang
     * @return string
     */
    public static function getLocaleByCompanyLang(int $lang): string
    {
        $locales = [
            1 => Locale::NL_NL,
            2 => Locale::NL_BE,
            3 => Locale::DE_DE,
            4 => Locale::FR_BE,
        ];

        return $locales[$lang] ?? Locale::NL_NL;
    }

    /**
     * @param  integer              $reference
     * @return array<string,string>
     */
    public static function getSiteDataByReference(int $reference, string $vehicleType): array
    {
        $default = self::isMotor($vehicleType) ? 4 : 1;
        $siteData = [
            Site::REF_CAR_NL => [
                'locale' => Locale::NL_NL,
                'vehicleType' => VehicleType::CAR,
                'labelName' => 'Ikwilvanmijnautoaf.nl',
            ],
            Site::REF_CAR_MARKTPLAATS_NL => [
                'locale' => Locale::NL_NL,
                'vehicleType' => VehicleType::CAR,
                'labelName' => 'Marktplaats Auto Verkoopservice',
            ],
            Site::REF_CAR_BE_NL => [
                'locale' => Locale::NL_BE,
                'vehicleType' => VehicleType::CAR,
                'labelName' => 'Ikwilvanmijnautoaf.be',
            ],
            Site::REF_MOTO_NL => [
                'locale' => Locale::NL_NL,
                'vehicleType' => VehicleType::MOTOR,
                'labelName' => 'Ikwilvanmijnmotoraf.nl',
            ],
            Site::REF_MOTO_BE => [
                'locale' => Locale::NL_BE,
                'vehicleType' => VehicleType::MOTOR,
                'labelName' => 'Ikwilvanmijnmotoraf.be',
            ],
            Site::REF_MOTO_DE => [
                'locale' => Locale::DE_DE,
                'vehicleType' => VehicleType::MOTOR,
                'labelName' => 'Ichwillmeinmotorradloswerden.de',
            ],
            Site::REF_SCOOTER_NL => [
                'locale' => Locale::NL_NL,
                'vehicleType' => VehicleType::SCOOTER,
                'labelName' => 'Ikwilvanmijnscooteraf.nl',
            ],
            Site::REF_BICYCLE_NL => [
                'locale' => Locale::NL_NL,
                'vehicleType' => VehicleType::BICYCLE,
                'labelName' => 'Ikwilvanmijnfietsaf.nl',
            ],
        ];

        return $siteData[$reference] ?? $siteData[$default];
    }

    /**
     * Gets the phone number by site reference
     *
     * @param  integer $reference
     * @return string
     */
    public static function getAgentPhoneByReference(int $reference): string
    {
        $agentPhones = [
            Site::REF_MOTO_NL => '053 - 20 844 49',
            Site::REF_MOTO_BE => '016 / 98.03.31',
            Site::REF_MOTO_DE => '02131 - 7 51 25 28',
            Site::REF_SCOOTER_NL => '053 - 208 44 49',
            Site::REF_BICYCLE_NL => '053 - 208 44 44',
            Site::REF_CAR_MARKTPLAATS_NL => '085 - 77 33 443',
        ];

        return $agentPhones[$reference] ?? $agentPhones[Site::REF_MOTO_NL];
    }

    /**
     * Formats date or return default value
     *
     * @param  string|null $date
     * @param  string      $format
     * @param  string      $default
     * @return string
     */
    public static function formatDateOrDefault($date, string $format = 'd-m-Y', string $default = '-'): string
    {
        return empty($date)
            ? $default
            : (new DateTime($date))->format($format);
    }

    /**
     * Translates gender to salutation
     *
     * @param  string  $locale
     * @param  integer $gender
     * @return string
     */
    public static function getSalutationByGender(string $locale, int $gender): string
    {
        Locale::assertExists($locale);
        Gender::assertExists($gender);

        if (Gender::UNKNOWN === $gender) {
            return '';
        }

        return match ($locale) {
            Locale::DE_DE => Gender::FEMALE === $gender ? 'Sehr geehrte Frau' : 'Sehr geehrter Herr',
            Locale::FR_BE,
            Locale::FR_FR => Gender::FEMALE === $gender ? 'Chère madame' : 'Cher monsieur',
            default => '',
        };
    }

    /**
     * @param array<string,string|int>|string|null $answer
     */
    public static function formatSurveyAnswer(array|string|null $answer): string
    {
        if (is_string($answer) || is_null($answer)) {
            return trim($answer ?? '');
        }

        return trim(
            sprintf(
                '%s%s %s',
                trim($answer['answer'] ?? ''),
                !empty($answer['answer']) && !empty($answer['comment']) ? ':' : '',
                trim($answer['comment'] ?? '')
            )
        );
    }

    public static function getVehicleTypeBySiteReference(int $siteReference): string
    {
        return match ($siteReference) {
            Site::REF_BICYCLE_NL => VehicleType::BICYCLE,
            Site::REF_CAR_NL,
            Site::REF_CAR_BE_NL,
            Site::REF_CAR_MARKTPLAATS_NL => VehicleType::CAR,
            Site::REF_MOTO_NL,
            Site::REF_MOTO_BE,
            Site::REF_MOTO_DE => VehicleType::MOTOR,
            Site::REF_SCOOTER_NL => VehicleType::SCOOTER,
            default => throw new \InvalidArgumentException("Unknown site reference: $siteReference"),
        };
    }

    public static function encrypt(string $encryptionKey, string|int $value): ?string
    {
        $key = new SymmetricKey(base64_decode($encryptionKey));

        return !empty($value)
            ? Version4::encrypt($value, $key)
            : null;
    }

    public static function getTranslator(DataObjects\SalesAgreement|DataObjects\PurchaseAgreement $data): Translator
    {
        try {
            return Translator::getInstance();
        } catch (\LogicException $e) {
            // Leave empty
        }

        return Translator::create($data->siteReference);
    }

    public static function getConsumerPrice(int $salesPrice, int $salesFee): int
    {
        return $salesPrice - $salesFee;
    }

    public static function formatNumber(int $number): string
    {
        return number_format($number, thousands_separator: '.');
    }

    public static function dateTimeOrNull(?string $date): ?DateTime
    {
        return empty($date) ? null : new DateTime($date);
    }
}
