<?php

declare(strict_types=1);

namespace Plugin\tnt_international_phone\src\Service;

/**
 * Scans a form POST for phone fields, normalizes valid numbers to E.164 in place
 * and records invalid ones (for the plausi hooks + the admin audit report).
 */
final class PhoneSubmissionHandler
{
    public const CONTEXT_ADDRESS = 'address';
    public const CONTEXT_CONTACT = 'contact';

    private const PHONE_FIELDS = ['tel', 'mobil', 'fax'];

    /** Field that carries a mobile number; subject to the mobile-only check. */
    private const MOBILE_FIELD = 'mobil';

    /** Values this short are cleared client-side too; treat as "not provided". */
    private const MIN_LENGTH = 5;

    /** @var array<string, int> template field name => error code (2 = invalidTel) */
    private array $invalidFields = [];

    public function __construct(
        private readonly PhoneValidator $validator,
        private readonly InvalidPhoneLoggerInterface $logger,
        private readonly ModifiedPhoneLoggerInterface $modifiedLogger,
        private readonly string $defaultRegion,
        private readonly bool $requireMobile = false
    ) {
    }

    /**
     * @param array<string, mixed> $post
     * @param list<string>         $contexts contexts this call may handle
     */
    public function process(array &$post, array $contexts): void
    {
        $context = isset($post['kontakt']) ? self::CONTEXT_CONTACT : self::CONTEXT_ADDRESS;
        if (!in_array($context, $contexts, true)) {
            return;
        }
        $region = $this->regionFrom($post['land'] ?? null);
        foreach (self::PHONE_FIELDS as $field) {
            if (isset($post[$field]) && is_string($post[$field])) {
                $this->handleField($post[$field], $field, $region, $context);
            }
        }
        if (isset($post['register']['shipping_address']) && is_array($post['register']['shipping_address'])) {
            $shipping       = &$post['register']['shipping_address'];
            $shippingRegion = $this->regionFrom($shipping['land'] ?? null);
            foreach (self::PHONE_FIELDS as $field) {
                if (isset($shipping[$field]) && is_string($shipping[$field])) {
                    $this->handleField($shipping[$field], $field, $shippingRegion, $context . '_shipping');
                }
            }
            unset($shipping);
        }
    }

    public function hasInvalid(): bool
    {
        return $this->invalidFields !== [];
    }

    /**
     * @return array<string, int> field name (as used in fehlendeAngaben) => error code
     */
    public function getInvalidFields(): array
    {
        return $this->invalidFields;
    }

    private function handleField(string &$value, string $field, string $region, string $form): void
    {
        $raw = trim($value);
        if (mb_strlen($raw) < self::MIN_LENGTH) {
            return;
        }
        $mustBeMobile = $this->requireMobile && $field === self::MOBILE_FIELD;
        $result       = $this->validator->check($raw, $region, $mustBeMobile);
        if ($result['valid'] && $result['e164'] !== null) {
            if ($result['e164'] !== $raw) {
                $this->modifiedLogger->log($form, $field, $raw, $result['e164'], $region);
            }
            $value = $result['e164'];

            return;
        }
        $this->invalidFields[$field] = 2;
        $this->logger->log($form, $field, $raw, $region, (string)$result['reason']);
    }

    private function regionFrom(mixed $land): string
    {
        return is_string($land) && $land !== '' ? strtoupper($land) : strtoupper($this->defaultRegion);
    }
}
