<?php

declare(strict_types=1);

namespace App\Modules\Guest;

/**
 * GuestValidator — Row-level validator for Guest records.
 *
 * Validates individual guest names, phone numbers, groups, and pax boundaries.
 * No database interactions are performed within the validator.
 *
 * @package Inveetaire
 * @ref     PILOT-002
 */
class GuestValidator
{
    // Allowed values for the guest_group column from schema constraints
    private const ALLOWED_GROUPS = [
        'family', 'relatives', 'friends', 'colleagues', 
        'church', 'business_partners', 'vip', 'others'
    ];

    /**
     * Validate raw guest row data.
     *
     * @param array $data Assumed mapped structure of row inputs.
     * @return array<string, string> Keyed error messages; empty if valid.
     */
    public function validateRow(array $data): array
    {
        $errors = [];

        // 1. Guest Full Name (Required)
        $fullName = isset($data['full_name']) ? trim((string) $data['full_name']) : '';
        if ($fullName === '') {
            $errors['full_name'] = 'Guest name is required.';
        } elseif (mb_strlen($fullName) > 150) {
            $errors['full_name'] = 'Guest name must not exceed 150 characters.';
        }

        // Honorific / Prefix (Optional) (G006)
        $honorific = isset($data['honorific']) ? trim((string) $data['honorific']) : '';
        if ($honorific !== '' && mb_strlen($honorific) > 50) {
            $errors['honorific'] = 'Honorific/Prefix must not exceed 50 characters.';
        }

        // 2. Phone Number (Optional)
        $phoneNumber = isset($data['phone_number']) ? trim((string) $data['phone_number']) : '';
        if ($phoneNumber !== '') {
            // Strip common symbols like spaces, dashes, parentheses
            $sanitizedPhone = preg_replace('/[\s\-\(\)]/', '', $phoneNumber);
            if (!preg_match('/^\+?[0-9]{5,20}$/', $sanitizedPhone)) {
                $errors['phone_number'] = "Invalid phone number format: '{$phoneNumber}'.";
            }
        }

        // 3. Pax (Optional, positive integer)
        if (isset($data['invited_pax'])) {
            $paxVal = $data['invited_pax'];
            if ($paxVal !== '' && $paxVal !== null) {
                $paxInt = filter_var($paxVal, FILTER_VALIDATE_INT);
                if ($paxInt === false || $paxInt < 1 || $paxInt > 255) {
                    $errors['invited_pax'] = "Pax must be a positive integer between 1 and 255 (got '{$paxVal}').";
                }
            }
        }

        // 4. Group (Optional, must be in enum)
        $group = isset($data['guest_group']) ? strtolower(trim((string) $data['guest_group'])) : '';
        if ($group !== '') {
            // Map variations of headers / values if close (family, relative, friend, colleague, partner)
            $resolvedGroup = $this->resolveGroupSlug($group);
            if (!in_array($resolvedGroup, self::ALLOWED_GROUPS, true)) {
                $errors['guest_group'] = "Invalid guest group '{$group}'. Allowed: " . implode(', ', self::ALLOWED_GROUPS) . ".";
            }
        }

        return $errors;
    }

    /**
     * Validate canonical guest_code format for persisted Guest entities.
     * Format: Exactly 5 characters, Uppercase A–Z, Digits 0–9 (Regex: ^[A-Z0-9]{5}$)
     *
     * @param string $code
     * @return bool
     */
    public function validateGuestCode(string $code): bool
    {
        return (bool) preg_match('/^[A-Z0-9]{5}$/', $code);
    }

    /**
     * Resolve spelling variations to allowed schema slugs.
     *
     * @param string $group
     * @return string
     */
    public function resolveGroupSlug(string $group): string
    {
        $g = strtolower(trim($group));
        
        // Match common variations
        if (in_array($g, ['family', 'keluarga'], true)) {
            return 'family';
        }
        if (in_array($g, ['relatives', 'relative', 'kerabat', 'saudara'], true)) {
            return 'relatives';
        }
        if (in_array($g, ['friends', 'friend', 'teman', 'sahabat'], true)) {
            return 'friends';
        }
        if (in_array($g, ['colleagues', 'colleague', 'rekan', 'kerja', 'teman kerja'], true)) {
            return 'colleagues';
        }
        if (in_array($g, ['church', 'jemaat', 'gereja'], true)) {
            return 'church';
        }
        if (in_array($g, ['business_partners', 'partner', 'rekan bisnis', 'business'], true)) {
            return 'business_partners';
        }
        if (in_array($g, ['vip', 'important'], true)) {
            return 'vip';
        }
        
        return $g;
    }
}
