<?php

namespace Inoby;

class Validator {
  /**
   * Error messages for validation
   */
  private array $error_messages;

  /**
   * Array containing key as input name and value as validation rule(s)
   */
  private array $fields_rules;

  /**
   * Array containing pretty field names for error messages
   * For ex. ["email" => "e-mail address"]
   */
  private array $fields_names;

  /**
   * Validator constructor
   *
   * @param array $fields_rules Array containing key as input name and value as validation rule(s)
   * @param array $fields_names Array containing pretty field names for error messages
   *                            For ex. ["email" => "e-mail address"]
   */
  public function __construct(array $fields_rules, array $fields_names = null) {
    // set fields rules
    $this->fields_rules = $fields_rules;

    // set fields names as fields (prevent undefined indexes)
    // then set user defined names if provided
    $this->fields_names = array_combine(array_keys($fields_rules), array_keys($fields_rules));
    if ($fields_names) {
      $this->set_fields_names($fields_names);
    }

    // set error messages
    $this->error_messages = [
      "required" => __("Pole {field} je vyžadované", "inoby"),
      "email" => __("Pole {field} musí byť platná emailová adresa.", "inoby"),
    ];
  }

  /**
   * Set user defined fields names, only those fields which are
   * provided are set to prevent undefined indexes.
   *
   * @param array $fields_names Array containing pretty field names for error messages
   *                            For ex. ["email" => "e-mail address"]
   */
  public function set_fields_names(array $fields_names): Validator {
    $this->fields_names = array_replace_recursive($this->fields_names, $fields_names);
    return $this;
  }

  /**
   * Validate field with specified rules
   *
   * @param string $field Field name from request
   * @param array $rules Rules to validate field with
   */
  private function validate_field(string $field, array $rules): array {
    foreach ($rules as $rule) {
      $has_error = false;

      switch ($rule) {
        case "required":
          $has_error = !isset($_POST[$field]) || empty($_POST[$field]);
          break;
        case "email":
          $has_error = !is_email($_POST[$field]);
          break;
      }

      if ($has_error) {
        $error = $this->get_error_for($field, $rule);
        return $error;
      }
    }

    return [];
  }

  /**
   * Get array containing field name and error message for specified rule.
   *
   * @param string $field Field name from request
   * @param string $rule Validation rule
   */
  private function get_error_for(string $field, string $rule): array {
    $message = str_replace("{field}", $this->fields_names[$field], $this->error_messages[$rule]);

    return [
      "field" => $field,
      "message" => $message,
    ];
  }

  /**
   * Validate all registered fields with their corresponding validation rules.
   *
   * @return array Empty array when validation succeeded,
   *               otherwise array containing errors.
   */
  public function validate(): array {
    $validated = [];
    foreach ($this->fields_rules as $field => $rules) {
      if (is_string($rules)) {
        $rules = explode(",", $rules);
      }
      $errors = $this->validate_field($field, $rules);
      if (!empty($errors)) {
        $validated[] = $errors;
      }
    }

    return $validated;
  }
}
