<?php

declare(strict_types=1);

namespace KupShop\ComponentsBundle\Twig\Components\UserLogin;

use KupShop\UserBundle\Exception\PhoneValidationException;
use KupShop\UserBundle\Util\PhoneNumberValidator;
use Symfony\Component\Form\Exception\UnexpectedTypeException;
use Symfony\Component\Translation\TranslatableMessage;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\Constraints\Email;
use Symfony\Component\Validator\ConstraintValidator;
use Symfony\Component\Validator\Validation;

class EmailOrPhoneValidator extends ConstraintValidator
{
    public function __construct(
        protected PhoneNumberValidator $phoneNumberValidator,
    ) {
    }

    public function validate(mixed $value, Constraint $constraint): void
    {
        if (!$constraint instanceof EmailOrPhone) {
            throw new UnexpectedTypeException($constraint, EmailOrPhone::class);
        }

        if (null === $value || '' === $value) {
            return;
        }

        if (!is_string($value)) {
            $this->context->buildViolation(new TranslatableMessage($constraint->message, [
                '{{ value }}' => $this->formatValue($value),
            ]))->addViolation();

            return;
        }

        // Check if it's a valid email
        $emailConstraint = Validation::createValidator()->validate($value, [
            new Email(),
        ]);

        if ($emailConstraint->count() == 0) {
            // Valid email, no need to check further
            return;
        }

        if (!findModule(\Modules::USERS, \Modules::SUB_USERS_PHONE_LOGIN)) {
            // Add invalid email message if modules not active
            $this->context->addViolation($emailConstraint->get(0)->getMessage());

            return;
        }

        // If not an email, check if it's a valid phone number
        try {
            $formattedPhoneNumber = $this->phoneNumberValidator->validate($value);
        } catch (PhoneValidationException $e) {
            $this->context->buildViolation(new TranslatableMessage($constraint->message, [
                '{{ value }}' => $this->formatValue($value),
            ]))->addViolation();

            return;
        }

        // If it's a phone number, ensure the normalized format
        $object = $this->context->getObject();
        if (is_object($object) && property_exists($object, 'login')) {
            $object->login = $formattedPhoneNumber->dbNumber;
        }
    }
}
