<?php

/**

 * Data Validation Engine

 */



class DataValidator {

    private $conn;

    private $rules;

    

    public function __construct($conn) {

        $this->conn = $conn;

        static $rulesCache = null;

        if ($rulesCache === null) {

            $rulesCache = require __DIR__ . '/rules.php';

        }

        $this->rules = $rulesCache;

    }

    

    public function validate($data, $type) {

        if (!isset($this->rules[$type])) {

            return ['valid' => true, 'errors' => [], 'warnings' => 0, 'suggestions' => []];

        }



        $errors = [];

        $rules = $this->rules[$type];



        foreach ($rules as $field => $fieldRules) {

            $rawValue = $data[$field] ?? null;

            // Only normalize N/A/blank/- to null for fields without a required rule.

            // Required fields keep N/A as a non-empty string so they pass the required check.

            $isRequired = !empty($fieldRules['required']);

            $value = (!$isRequired && is_string($rawValue) && (trim($rawValue) === '' || strtoupper(trim($rawValue)) === 'N/A' || trim($rawValue) === '-'))

                ? null : $rawValue;



            foreach ($fieldRules as $rule => $params) {

                $result = $this->applyRule($value, $rule, $params, $data);

                if ($result !== true) {

                    $errors[] = [

                        'field' => $field,

                        'rule' => $rule,

                        'message' => $result

                    ];

                }

            }

        }



        return [

            'valid'       => empty($errors),

            'errors'      => $errors,

            'warnings'    => 0,

            'suggestions' => [],

        ];

    }

    

    private function applyRule($value, $rule, $params, $context) {

        // Skip all optional-field rules when the value is absent/null

        if ($value === null && $rule !== 'required') {

            return true;

        }



        switch ($rule) {

            case 'required':

                if (empty($value)) {

                    return "This field is required";

                }

                break;

                

            case 'numeric':

                if (!is_numeric($value)) {

                    return "Must be a number";

                }

                break;

                

            case 'min':

                if (is_numeric($value) && $value < $params) {

                    return "Must be at least $params";

                }

                break;

                

            case 'max':

                if (is_numeric($value) && $value > $params) {

                    return "Must not exceed $params";

                }

                break;

                

            case 'date':

                if (!DateTime::createFromFormat('Y-m-d', $value)) {

                    return "Invalid date format (use YYYY-MM-DD)";

                }

                break;

                

            case 'email':

                if (!filter_var($value, FILTER_VALIDATE_EMAIL)) {

                    return "Invalid email address";

                }

                break;

                

            case 'phone':

                $cleaned = preg_replace('/[^0-9]/', '', $value);

                if (strlen($cleaned) < 9 || strlen($cleaned) > 12) {

                    return "Invalid phone number length";

                }

                break;

                

            case 'unique':

                if (!empty($value)) {

                    $table = $params['table'];

                    $field = $params['field'];

                    $query = "SELECT id FROM $table WHERE $field = ?";

                    $stmt = $this->conn->prepare($query);

                    $stmt->bind_param("s", $value);

                    $stmt->execute();

                    $result = $stmt->get_result();

                    if ($result->num_rows > 0) {

                        return "This value already exists";

                    }

                }

                break;

                

            case 'exists':

                if (!empty($value)) {

                    $table = $params['table'];

                    $field = $params['field'];

                    $query = "SELECT id FROM $table WHERE $field = ?";

                    $stmt = $this->conn->prepare($query);

                    $stmt->bind_param("s", $value);

                    $stmt->execute();

                    $result = $stmt->get_result();

                    if ($result->num_rows == 0) {

                        return "Referenced record does not exist";

                    }

                }

                break;

        }

        

        return true;

    }

}



?>