<?php
/**
 * Input Validator Utility
 *
 * Comprehensive input validation for all API endpoints
 *
 * @package Care_API
 * @subpackage Utils
 * @version    1.0.0
 * @author     Descomplicar® <dev@descomplicar.pt>
 * @link       https://descomplicar.pt
 * @since      1.0.0
 */

namespace Care_API\Utils;

use WP_Error;

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

/**
 * Class Input_Validator
 *
 * Centralized input validation for all API operations
 *
 * @since 1.0.0
 */
class Input_Validator {

    /**
     * Validate clinic data
     *
     * @param array  $data      Data to validate
     * @param string $operation Operation type (create, update)
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    public static function validate_clinic_data( $data, $operation = 'create' ) {
        $errors = array();

        if ( $operation === 'create' ) {
            // Required fields for creation
            if ( empty( $data['name'] ) ) {
                $errors[] = 'Clinic name is required';
            }
        }

        // Validate email format if provided
        if ( ! empty( $data['email'] ) && ! is_email( $data['email'] ) ) {
            $errors[] = 'Invalid email format';
        }

        // Validate phone number format if provided
        if ( ! empty( $data['telephone_no'] ) && ! self::validate_phone_number( $data['telephone_no'] ) ) {
            $errors[] = 'Invalid phone number format';
        }

        // Validate specialties if provided
        if ( ! empty( $data['specialties'] ) && ! self::validate_specialties( $data['specialties'] ) ) {
            $errors[] = 'Invalid specialties format or values';
        }

        if ( ! empty( $errors ) ) {
            return new WP_Error(
                'clinic_validation_failed',
                'Clinic validation failed',
                array( 'status' => 400, 'errors' => $errors )
            );
        }

        return true;
    }

    /**
     * Validate patient data
     *
     * @param array  $data      Data to validate
     * @param string $operation Operation type (create, update)
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    public static function validate_patient_data( $data, $operation = 'create' ) {
        $errors = array();

        if ( $operation === 'create' ) {
            // Required fields for creation
            $required_fields = array( 'first_name', 'last_name', 'clinic_id' );
            foreach ( $required_fields as $field ) {
                if ( empty( $data[$field] ) ) {
                    $errors[] = ucfirst( str_replace( '_', ' ', $field ) ) . ' is required';
                }
            }
        }

        // Validate email format if provided
        if ( ! empty( $data['user_email'] ) && ! is_email( $data['user_email'] ) ) {
            $errors[] = 'Invalid email format';
        }

        // Validate phone number format if provided
        if ( ! empty( $data['contact_no'] ) && ! self::validate_phone_number( $data['contact_no'] ) ) {
            $errors[] = 'Invalid contact number format';
        }

        // Validate date of birth if provided
        if ( ! empty( $data['dob'] ) && ! self::validate_date( $data['dob'] ) ) {
            $errors[] = 'Invalid date of birth format';
        }

        // Validate gender if provided
        if ( ! empty( $data['gender'] ) && ! self::validate_gender( $data['gender'] ) ) {
            $errors[] = 'Invalid gender value';
        }

        if ( ! empty( $errors ) ) {
            return new WP_Error(
                'patient_validation_failed',
                'Patient validation failed',
                array( 'status' => 400, 'errors' => $errors )
            );
        }

        return true;
    }

    /**
     * Validate doctor data
     *
     * @param array  $data      Data to validate
     * @param string $operation Operation type (create, update)
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    public static function validate_doctor_data( $data, $operation = 'create' ) {
        $errors = array();

        if ( $operation === 'create' ) {
            // Required fields for creation
            $required_fields = array( 'first_name', 'last_name', 'clinic_id' );
            foreach ( $required_fields as $field ) {
                if ( empty( $data[$field] ) ) {
                    $errors[] = ucfirst( str_replace( '_', ' ', $field ) ) . ' is required';
                }
            }
        }

        // Validate email format if provided
        if ( ! empty( $data['user_email'] ) && ! is_email( $data['user_email'] ) ) {
            $errors[] = 'Invalid email format';
        }

        // Validate mobile number format if provided
        if ( ! empty( $data['mobile_number'] ) && ! self::validate_phone_number( $data['mobile_number'] ) ) {
            $errors[] = 'Invalid mobile number format';
        }

        // Validate specialties if provided
        if ( ! empty( $data['specialties'] ) && ! self::validate_specialties( $data['specialties'] ) ) {
            $errors[] = 'Invalid specialties format or values';
        }

        // Validate license number format if provided
        if ( ! empty( $data['license_number'] ) && ! self::validate_license_number( $data['license_number'] ) ) {
            $errors[] = 'Invalid license number format';
        }

        if ( ! empty( $errors ) ) {
            return new WP_Error(
                'doctor_validation_failed',
                'Doctor validation failed',
                array( 'status' => 400, 'errors' => $errors )
            );
        }

        return true;
    }

    /**
     * Validate appointment data
     *
     * @param array  $data      Data to validate
     * @param string $operation Operation type (create, update)
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    public static function validate_appointment_data( $data, $operation = 'create' ) {
        $errors = array();

        if ( $operation === 'create' ) {
            // Required fields for creation
            $required_fields = array( 'patient_id', 'doctor_id', 'clinic_id', 'appointment_start_date', 'appointment_start_time' );
            foreach ( $required_fields as $field ) {
                if ( empty( $data[$field] ) ) {
                    $errors[] = ucfirst( str_replace( '_', ' ', $field ) ) . ' is required';
                }
            }
        }

        // Validate appointment date if provided
        if ( ! empty( $data['appointment_start_date'] ) && ! self::validate_date( $data['appointment_start_date'] ) ) {
            $errors[] = 'Invalid appointment start date format';
        }

        // Validate appointment time if provided
        if ( ! empty( $data['appointment_start_time'] ) && ! self::validate_time( $data['appointment_start_time'] ) ) {
            $errors[] = 'Invalid appointment start time format';
        }

        // Validate end time if provided
        if ( ! empty( $data['appointment_end_time'] ) && ! self::validate_time( $data['appointment_end_time'] ) ) {
            $errors[] = 'Invalid appointment end time format';
        }

        // Validate duration if provided
        if ( ! empty( $data['duration'] ) && ! self::validate_duration( $data['duration'] ) ) {
            $errors[] = 'Invalid duration value';
        }

        // Validate status if provided
        if ( ! empty( $data['status'] ) && ! self::validate_appointment_status( $data['status'] ) ) {
            $errors[] = 'Invalid appointment status';
        }

        if ( ! empty( $errors ) ) {
            return new WP_Error(
                'appointment_validation_failed',
                'Appointment validation failed',
                array( 'status' => 400, 'errors' => $errors )
            );
        }

        return true;
    }

    /**
     * Validate encounter data
     *
     * @param array  $data      Data to validate
     * @param string $operation Operation type (create, update)
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    public static function validate_encounter_data( $data, $operation = 'create' ) {
        $errors = array();

        if ( $operation === 'create' ) {
            // Required fields for creation
            $required_fields = array( 'patient_id', 'doctor_id', 'clinic_id' );
            foreach ( $required_fields as $field ) {
                if ( empty( $data[$field] ) ) {
                    $errors[] = ucfirst( str_replace( '_', ' ', $field ) ) . ' is required';
                }
            }
        }

        // Validate encounter date if provided
        if ( ! empty( $data['encounter_date'] ) && ! self::validate_datetime( $data['encounter_date'] ) ) {
            $errors[] = 'Invalid encounter date format';
        }

        // Validate status if provided
        if ( ! empty( $data['status'] ) && ! self::validate_encounter_status( $data['status'] ) ) {
            $errors[] = 'Invalid encounter status';
        }

        // Validate SOAP notes if provided
        if ( ! empty( $data['soap_notes'] ) && ! self::validate_soap_notes( $data['soap_notes'] ) ) {
            $errors[] = 'Invalid SOAP notes format';
        }

        // Validate vital signs if provided
        if ( ! empty( $data['vital_signs'] ) && ! self::validate_vital_signs( $data['vital_signs'] ) ) {
            $errors[] = 'Invalid vital signs format';
        }

        if ( ! empty( $errors ) ) {
            return new WP_Error(
                'encounter_validation_failed',
                'Encounter validation failed',
                array( 'status' => 400, 'errors' => $errors )
            );
        }

        return true;
    }

    /**
     * Validate prescription data
     *
     * @param array  $data      Data to validate
     * @param string $operation Operation type (create, update)
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    public static function validate_prescription_data( $data, $operation = 'create' ) {
        $errors = array();

        if ( $operation === 'create' ) {
            // Required fields for creation
            $required_fields = array( 'patient_id', 'doctor_id', 'medication_name', 'dosage', 'frequency' );
            foreach ( $required_fields as $field ) {
                if ( empty( $data[$field] ) ) {
                    $errors[] = ucfirst( str_replace( '_', ' ', $field ) ) . ' is required';
                }
            }
        }

        // Validate prescription date if provided
        if ( ! empty( $data['prescription_date'] ) && ! self::validate_date( $data['prescription_date'] ) ) {
            $errors[] = 'Invalid prescription date format';
        }

        // Validate dosage format if provided
        if ( ! empty( $data['dosage'] ) && ! self::validate_dosage( $data['dosage'] ) ) {
            $errors[] = 'Invalid dosage format';
        }

        // Validate frequency if provided
        if ( ! empty( $data['frequency'] ) && ! self::validate_frequency( $data['frequency'] ) ) {
            $errors[] = 'Invalid frequency format';
        }

        // Validate duration if provided
        if ( ! empty( $data['duration_days'] ) && ! self::validate_positive_integer( $data['duration_days'] ) ) {
            $errors[] = 'Duration must be a positive integer';
        }

        // Validate status if provided
        if ( ! empty( $data['status'] ) && ! self::validate_prescription_status( $data['status'] ) ) {
            $errors[] = 'Invalid prescription status';
        }

        if ( ! empty( $errors ) ) {
            return new WP_Error(
                'prescription_validation_failed',
                'Prescription validation failed',
                array( 'status' => 400, 'errors' => $errors )
            );
        }

        return true;
    }

    /**
     * Validate bill data
     *
     * @param array  $data      Data to validate
     * @param string $operation Operation type (create, update)
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    public static function validate_bill_data( $data, $operation = 'create' ) {
        $errors = array();

        if ( $operation === 'create' ) {
            // Required fields for creation
            $required_fields = array( 'patient_id', 'clinic_id' );
            foreach ( $required_fields as $field ) {
                if ( empty( $data[$field] ) ) {
                    $errors[] = ucfirst( str_replace( '_', ' ', $field ) ) . ' is required';
                }
            }
        }

        // Validate bill date if provided
        if ( ! empty( $data['bill_date'] ) && ! self::validate_date( $data['bill_date'] ) ) {
            $errors[] = 'Invalid bill date format';
        }

        // Validate due date if provided
        if ( ! empty( $data['due_date'] ) && ! self::validate_date( $data['due_date'] ) ) {
            $errors[] = 'Invalid due date format';
        }

        // Validate amounts if provided
        $amount_fields = array( 'subtotal_amount', 'tax_amount', 'discount_amount', 'total_amount', 'amount_paid' );
        foreach ( $amount_fields as $field ) {
            if ( isset( $data[$field] ) && ! self::validate_currency_amount( $data[$field] ) ) {
                $errors[] = "Invalid {$field} format";
            }
        }

        // Validate status if provided
        if ( ! empty( $data['status'] ) && ! self::validate_bill_status( $data['status'] ) ) {
            $errors[] = 'Invalid bill status';
        }

        // Validate items if provided
        if ( ! empty( $data['items'] ) && ! self::validate_bill_items( $data['items'] ) ) {
            $errors[] = 'Invalid bill items format';
        }

        if ( ! empty( $errors ) ) {
            return new WP_Error(
                'bill_validation_failed',
                'Bill validation failed',
                array( 'status' => 400, 'errors' => $errors )
            );
        }

        return true;
    }

    /**
     * Validate clinic list parameters
     *
     * @param array $params Parameters to validate
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    public static function validate_clinic_list_params( $params ) {
        $errors = array();

        // Validate page parameter
        if ( isset( $params['page'] ) && ( ! is_numeric( $params['page'] ) || $params['page'] < 1 ) ) {
            $errors[] = 'Page must be a positive integer';
        }

        // Validate per_page parameter
        if ( isset( $params['per_page'] ) && ( ! is_numeric( $params['per_page'] ) || $params['per_page'] < 1 || $params['per_page'] > 100 ) ) {
            $errors[] = 'Per page must be between 1 and 100';
        }

        // Validate status parameter
        if ( isset( $params['status'] ) && ! in_array( $params['status'], array( 0, 1, '0', '1' ) ) ) {
            $errors[] = 'Status must be 0 or 1';
        }

        if ( ! empty( $errors ) ) {
            return new WP_Error(
                'list_params_validation_failed',
                'List parameters validation failed',
                array( 'status' => 400, 'errors' => $errors )
            );
        }

        return true;
    }

    /**
     * Sanitize clinic data
     *
     * @param array $data Data to sanitize
     * @return array Sanitized data
     * @since 1.0.0
     */
    public static function sanitize_clinic_data( $data ) {
        $sanitized = array();

        $text_fields = array( 'name', 'address', 'city', 'state', 'country', 'postal_code', 'telephone_no' );
        foreach ( $text_fields as $field ) {
            if ( isset( $data[$field] ) ) {
                $sanitized[$field] = sanitize_text_field( $data[$field] );
            }
        }

        if ( isset( $data['email'] ) ) {
            $sanitized['email'] = sanitize_email( $data['email'] );
        }

        if ( isset( $data['specialties'] ) && is_array( $data['specialties'] ) ) {
            $sanitized['specialties'] = array_map( 'sanitize_text_field', $data['specialties'] );
        }

        if ( isset( $data['clinic_admin_id'] ) ) {
            $sanitized['clinic_admin_id'] = absint( $data['clinic_admin_id'] );
        }

        if ( isset( $data['status'] ) ) {
            $sanitized['status'] = absint( $data['status'] );
        }

        return $sanitized;
    }

    /**
     * Sanitize patient data
     *
     * @param array $data Data to sanitize
     * @return array Sanitized data
     * @since 1.0.0
     */
    public static function sanitize_patient_data( $data ) {
        $sanitized = array();

        $text_fields = array( 'first_name', 'last_name', 'patient_id', 'contact_no', 'address', 'city', 'state', 'country', 'postal_code', 'gender', 'blood_group', 'emergency_contact_name', 'emergency_contact_no' );
        foreach ( $text_fields as $field ) {
            if ( isset( $data[$field] ) ) {
                $sanitized[$field] = sanitize_text_field( $data[$field] );
            }
        }

        if ( isset( $data['user_email'] ) ) {
            $sanitized['user_email'] = sanitize_email( $data['user_email'] );
        }

        if ( isset( $data['dob'] ) ) {
            $sanitized['dob'] = sanitize_text_field( $data['dob'] );
        }

        if ( isset( $data['clinic_id'] ) ) {
            $sanitized['clinic_id'] = absint( $data['clinic_id'] );
        }

        if ( isset( $data['status'] ) ) {
            $sanitized['status'] = absint( $data['status'] );
        }

        return $sanitized;
    }

    /**
     * Validation helper methods
     */

    private static function validate_phone_number( $phone ) {
        return preg_match( '/^[+]?[0-9\s\-\(\)]{7,20}$/', $phone );
    }

    private static function validate_specialties( $specialties ) {
        if ( ! is_array( $specialties ) ) {
            return false;
        }

        $valid_specialties = array(
            'general_medicine', 'cardiology', 'dermatology', 'endocrinology',
            'gastroenterology', 'gynecology', 'neurology', 'oncology',
            'ophthalmology', 'orthopedics', 'otolaryngology', 'pediatrics',
            'psychiatry', 'pulmonology', 'radiology', 'urology', 'surgery',
            'anesthesiology', 'pathology', 'emergency_medicine', 'family_medicine'
        );

        foreach ( $specialties as $specialty ) {
            if ( ! in_array( $specialty, $valid_specialties ) ) {
                return false;
            }
        }

        return true;
    }

    private static function validate_date( $date ) {
        $d = \DateTime::createFromFormat( 'Y-m-d', $date );
        return $d && $d->format( 'Y-m-d' ) === $date;
    }

    private static function validate_datetime( $datetime ) {
        $d = \DateTime::createFromFormat( 'Y-m-d H:i:s', $datetime );
        return $d && $d->format( 'Y-m-d H:i:s' ) === $datetime;
    }

    private static function validate_time( $time ) {
        return preg_match( '/^([0-1]?[0-9]|2[0-3]):[0-5][0-9](:[0-5][0-9])?$/', $time );
    }

    private static function validate_gender( $gender ) {
        return in_array( strtolower( $gender ), array( 'male', 'female', 'other' ) );
    }

    private static function validate_duration( $duration ) {
        return is_numeric( $duration ) && $duration > 0 && $duration <= 480; // Max 8 hours
    }

    private static function validate_appointment_status( $status ) {
        return in_array( $status, array( 1, 2, 3, 4, 5 ) ); // Booked, Completed, Cancelled, No Show, Rescheduled
    }

    private static function validate_encounter_status( $status ) {
        return in_array( $status, array( 'draft', 'in_progress', 'finalized' ) );
    }

    private static function validate_soap_notes( $soap_notes ) {
        if ( ! is_array( $soap_notes ) ) {
            return false;
        }

        $valid_sections = array( 'subjective', 'objective', 'assessment', 'plan' );
        foreach ( array_keys( $soap_notes ) as $section ) {
            if ( ! in_array( $section, $valid_sections ) ) {
                return false;
            }
        }

        return true;
    }

    private static function validate_vital_signs( $vital_signs ) {
        if ( ! is_array( $vital_signs ) ) {
            return false;
        }

        $valid_vitals = array( 'temperature', 'blood_pressure_systolic', 'blood_pressure_diastolic', 'heart_rate', 'respiratory_rate', 'oxygen_saturation', 'weight', 'height', 'bmi' );
        
        foreach ( array_keys( $vital_signs ) as $vital ) {
            if ( ! in_array( $vital, $valid_vitals ) ) {
                return false;
            }
        }

        return true;
    }

    private static function validate_dosage( $dosage ) {
        return preg_match( '/^\d+(\.\d+)?\s*(mg|g|ml|units?)$/i', $dosage );
    }

    private static function validate_frequency( $frequency ) {
        $valid_frequencies = array(
            'once daily', 'twice daily', 'three times daily', 'four times daily',
            'every 4 hours', 'every 6 hours', 'every 8 hours', 'every 12 hours',
            'as needed', 'before meals', 'after meals', 'at bedtime'
        );
        
        return in_array( strtolower( $frequency ), $valid_frequencies );
    }

    private static function validate_prescription_status( $status ) {
        return in_array( $status, array( 'active', 'completed', 'cancelled', 'discontinued' ) );
    }

    private static function validate_bill_status( $status ) {
        return in_array( $status, array( 'draft', 'pending', 'paid', 'overdue', 'cancelled', 'refunded' ) );
    }

    private static function validate_currency_amount( $amount ) {
        return is_numeric( $amount ) && $amount >= 0;
    }

    private static function validate_positive_integer( $value ) {
        return is_numeric( $value ) && $value > 0 && $value == (int) $value;
    }

    private static function validate_license_number( $license ) {
        return preg_match( '/^[A-Z0-9\-]{5,20}$/', $license );
    }

    private static function validate_bill_items( $items ) {
        if ( ! is_array( $items ) ) {
            return false;
        }

        foreach ( $items as $item ) {
            if ( ! is_array( $item ) ) {
                return false;
            }

            $required_fields = array( 'name', 'quantity', 'unit_price' );
            foreach ( $required_fields as $field ) {
                if ( ! isset( $item[$field] ) ) {
                    return false;
                }
            }

            if ( ! is_numeric( $item['quantity'] ) || $item['quantity'] <= 0 ) {
                return false;
            }

            if ( ! is_numeric( $item['unit_price'] ) || $item['unit_price'] < 0 ) {
                return false;
            }
        }

        return true;
    }
}