<?php
namespace OxygenApp\Common\Validation;

if ( ! defined( 'ABSPATH' ) ) exit;

class FieldsValidator {

    public static function validate(array $params, array $fieldRules, bool $allowUnexpectedFields = false): array {
        
        if (!$allowUnexpectedFields) {
            // allowed fields
            $allowedFields = array_map(fn($rule) => $rule['field_name'], $fieldRules);

            foreach ($params as $field => $value) {
                if (!in_array($field, $allowedFields)) {
                    return self::errorResponse("The field '{$field}' is not allowed.");
                }
            }
        }

        foreach ($fieldRules as $rule) {
            $field = $rule['field_name'];
            $value = $params[$field] ?? null;

            if (!empty($rule['required']) && empty($value)) {
                return self::errorResponse("The field '{$field}' is required.");
            }

            if ($value === null) continue;


            $validationResult = self::validateType($value, $rule);
            if (!$validationResult['status']) {
                return $validationResult;
            }
        }

        return ['status' => true]; // Validation passed
    }

    private static function validateType($value, array $rule): array {
        $field = $rule['field_name'];
        $type = $rule['type'] ?? 'string';

        switch ($type) {
            case 'email':
                if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {
                    return self::errorResponse(esc_html__('Invalid email format for', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $field);
                }
                break;

            case 'string':
                if (!is_string($value)) {
                    return self::errorResponse($field . ' ' .esc_html__('must be a string', 'oxyleaf-app-working-and-relaxing-app'));
                }
                if (isset($rule['min_length']) && strlen($value) < $rule['min_length']) {
                    return self::errorResponse($field . ' ' . esc_html__('must be at least', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['min_length'] . ' ' . esc_html__('characters long', 'oxyleaf-app-working-and-relaxing-app'));
                }

                if (isset($rule['max_length']) && strlen($value) > $rule['max_length']) {
                    return self::errorResponse($field . ' ' . esc_html__('must not exceed', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['max_length'] . ' ' . esc_html__('characters', 'oxyleaf-app-working-and-relaxing-app'));
                }
            case 'password':
                if (!is_string($value)) {
                    return self::errorResponse($field . ' ' .esc_html__('must be a string', 'oxyleaf-app-working-and-relaxing-app'));
                }

                if (isset($rule['min_length']) && strlen($value) < $rule['min_length']) {
                    return self::errorResponse($field . ' ' . esc_html__('must be at least', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['min_length'] . ' ' . esc_html__('characters long', 'oxyleaf-app-working-and-relaxing-app'));
                }

                if (isset($rule['max_length']) && strlen($value) > $rule['max_length']) {
                    return self::errorResponse($field . ' ' . esc_html__('must not exceed', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['max_length'] . ' ' . esc_html__('characters', 'oxyleaf-app-working-and-relaxing-app'));
                }

                if ($type === 'password') {
                    // At least one number
                    if (!preg_match('/\p{N}/u', $value)) {
                        return self::errorResponse($field . ' ' . esc_html__('must contain at least one number', 'oxyleaf-app-working-and-relaxing-app'));
                    }             
                }
                break;

            case 'int':
                if (!filter_var($value, FILTER_VALIDATE_INT)) {
                    return self::errorResponse($field . ' ' . esc_html__('must be an integer', 'oxyleaf-app-working-and-relaxing-app'));
                }

                $intValue = (int) $value;

                if (isset($rule['min_value']) && $intValue < $rule['min_value']) {
                    return self::errorResponse($field . ' ' . esc_html__('must be at least', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['min_value']);
                }

                if (isset($rule['max_value']) && $intValue > $rule['max_value']) {
                    return self::errorResponse($field . ' ' . esc_html__('must not exceed', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['max_value']);
                }
                break;

            case 'float':
                if (!filter_var($value, FILTER_VALIDATE_FLOAT)) {
                    return self::errorResponse($field . ' ' . esc_html__('must be a float', 'oxyleaf-app-working-and-relaxing-app'));
                }
                $floatValue = (float) $value;
                if (isset($rule['min_value']) && $floatValue < $rule['min_value']) {
                    return self::errorResponse($field . ' ' . esc_html__('must be at least', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['min_value']);
                }
                if (isset($rule['max_value']) && $floatValue > $rule['max_value']) {
                    return self::errorResponse($field . ' ' . esc_html__('must not exceed', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['max_value']);
                }
                break;

            case 'array':
                if (!is_array($value)) {
                    return self::errorResponse($field . ' ' . esc_html__('must be an array', 'oxyleaf-app-working-and-relaxing-app'));
                }
                if (isset($rule['max_length']) && count($value) > $rule['max_length']) {
                    return self::errorResponse($field . ' ' . esc_html__('must not exceed', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $rule['max_length'] . ' ' . esc_html__('items', 'oxyleaf-app-working-and-relaxing-app'));
                }
                if (!empty($rule['item_rules']) && is_array($rule['item_rules'])) {
                    foreach ($value as $index => $item) {
                        foreach ($rule['item_rules'] as $itemRule) {
                            if (!isset($item[$itemRule['field_name']])) {
                                return self::errorResponse($field . "[$index] " . esc_html__('is missing required field', 'oxyleaf-app-working-and-relaxing-app') . ' ' . $itemRule['field_name']);
                            }
                            $itemValidation = self::validateType($item[$itemRule['field_name']], $itemRule);
                            if (!$itemValidation['status']) {
                                return self::errorResponse($field . "[$index] " . $itemValidation['errorMessage']);
                            }
                        }
                    }
                }
                break;

            default:
                return self::errorResponse($field . ' ' . esc_html__('Unknown validation type', 'oxyleaf-app-working-and-relaxing-app'));
        }

        if (isset($rule['exact_value']) && $value !== $rule['exact_value']) {
            return self::errorResponse($field . ' ' . esc_html__('must have the exact value', 'oxyleaf-app-working-and-relaxing-app') . ': ' . $rule['exact_value']);
        }

        return ['status' => true];
    }

    private static function errorResponse(string $message): array {
        return [
            'status' => false,
            'errorMessage' => $message
        ];
    }
}