<?php
/**
 * Patient Database Service
 *
 * Handles advanced patient data operations and business logic
 *
 * @package Care_API
 * @subpackage Services\Database
 * @version    1.0.0
 * @author     Descomplicar® <dev@descomplicar.pt>
 * @link       https://descomplicar.pt
 * @since      1.0.0
 */

namespace Care_API\Services\Database;

use Care_API\Models\Patient;
use Care_API\Services\Permission_Service;

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

/**
 * Class Patient_Service
 *
 * Advanced database service for patient management with business logic
 *
 * @since 1.0.0
 */
class Patient_Service {

    /**
     * Initialize the service
     *
     * @since 1.0.0
     */
    public static function init() {
        // Hook into WordPress actions
        add_action( 'kivicare_patient_created', array( self::class, 'on_patient_created' ), 10, 2 );
        add_action( 'kivicare_patient_updated', array( self::class, 'on_patient_updated' ), 10, 2 );
        add_action( 'kivicare_patient_deleted', array( self::class, 'on_patient_deleted' ), 10, 1 );
    }

    /**
     * Create patient with advanced business logic
     *
     * @param array $patient_data Patient data
     * @param int   $clinic_id    Clinic ID
     * @param int   $user_id      Creating user ID
     * @return array|WP_Error Patient data or error
     * @since 1.0.0
     */
    public static function create_patient( $patient_data, $clinic_id, $user_id = null ) {
        // Permission check
        if ( ! Permission_Service::can_access_clinic( get_current_user_id(), $clinic_id ) ) {
            return new \WP_Error(
                'insufficient_permissions',
                'You do not have permission to create patients in this clinic',
                array( 'status' => 403 )
            );
        }

        // Enhanced validation
        $validation = self::validate_patient_business_rules( $patient_data, $clinic_id );
        if ( is_wp_error( $validation ) ) {
            return $validation;
        }

        // Add metadata
        $patient_data['clinic_id'] = $clinic_id;
        $patient_data['created_by'] = $user_id ?: get_current_user_id();
        $patient_data['created_at'] = current_time( 'mysql' );

        // Generate patient ID if not provided
        if ( empty( $patient_data['patient_id'] ) ) {
            $patient_data['patient_id'] = self::generate_patient_id( $clinic_id );
        }

        // Create patient
        $patient_id = Patient::create( $patient_data );
        
        if ( is_wp_error( $patient_id ) ) {
            return $patient_id;
        }

        // Post-creation tasks
        self::setup_patient_defaults( $patient_id, $patient_data );
        
        // Trigger action
        do_action( 'kivicare_patient_created', $patient_id, $patient_data );

        // Return full patient data
        return self::get_patient_with_metadata( $patient_id );
    }

    /**
     * Update patient with business logic
     *
     * @param int   $patient_id   Patient ID
     * @param array $patient_data Updated data
     * @return array|WP_Error Updated patient data or error
     * @since 1.0.0
     */
    public static function update_patient( $patient_id, $patient_data ) {
        // Get current patient data
        $current_patient = Patient::get_by_id( $patient_id );
        if ( ! $current_patient ) {
            return new \WP_Error(
                'patient_not_found',
                'Patient not found',
                array( 'status' => 404 )
            );
        }

        // Permission check
        if ( ! Permission_Service::can_access_clinic( get_current_user_id(), $current_patient['clinic_id'] ) ) {
            return new \WP_Error(
                'insufficient_permissions',
                'You do not have permission to update this patient',
                array( 'status' => 403 )
            );
        }

        // Enhanced validation
        $validation = self::validate_patient_business_rules( $patient_data, $current_patient['clinic_id'], $patient_id );
        if ( is_wp_error( $validation ) ) {
            return $validation;
        }

        // Add update metadata
        $patient_data['updated_by'] = get_current_user_id();
        $patient_data['updated_at'] = current_time( 'mysql' );

        // Update patient
        $result = Patient::update( $patient_id, $patient_data );
        
        if ( is_wp_error( $result ) ) {
            return $result;
        }

        // Handle emergency contact changes
        self::handle_emergency_contact_changes( $patient_id, $current_patient, $patient_data );

        // Trigger action
        do_action( 'kivicare_patient_updated', $patient_id, $patient_data );

        // Return updated patient data
        return self::get_patient_with_metadata( $patient_id );
    }

    /**
     * Get patient with enhanced metadata
     *
     * @param int $patient_id Patient ID
     * @return array|WP_Error Patient data with metadata or error
     * @since 1.0.0
     */
    public static function get_patient_with_metadata( $patient_id ) {
        $patient = Patient::get_by_id( $patient_id );
        
        if ( ! $patient ) {
            return new \WP_Error(
                'patient_not_found',
                'Patient not found',
                array( 'status' => 404 )
            );
        }

        // Permission check
        if ( ! Permission_Service::can_access_clinic( get_current_user_id(), $patient['clinic_id'] ) ) {
            return new \WP_Error(
                'access_denied',
                'You do not have access to this patient',
                array( 'status' => 403 )
            );
        }

        // Add enhanced metadata
        $patient['appointments'] = self::get_patient_appointments( $patient_id );
        $patient['encounters'] = self::get_patient_encounters( $patient_id );
        $patient['prescriptions'] = self::get_patient_prescriptions( $patient_id );
        $patient['bills'] = self::get_patient_bills( $patient_id );
        $patient['medical_history'] = self::get_patient_medical_history( $patient_id );
        $patient['emergency_contacts'] = self::get_patient_emergency_contacts( $patient_id );

        return $patient;
    }

    /**
     * Search patients with advanced criteria
     *
     * @param string $search_term Search term
     * @param int    $clinic_id   Clinic ID
     * @param array  $filters     Additional filters
     * @return array Search results
     * @since 1.0.0
     */
    public static function search_patients( $search_term, $clinic_id, $filters = array() ) {
        global $wpdb;

        // Permission check
        if ( ! Permission_Service::can_access_clinic( get_current_user_id(), $clinic_id ) ) {
            return array();
        }

        // Build search query
        $where_clauses = array( "p.clinic_id = %d" );
        $where_values = array( $clinic_id );

        // Search term
        if ( ! empty( $search_term ) ) {
            $where_clauses[] = "(p.first_name LIKE %s OR p.last_name LIKE %s OR p.patient_id LIKE %s OR p.contact_no LIKE %s OR p.user_email LIKE %s)";
            $search_term = '%' . $wpdb->esc_like( $search_term ) . '%';
            $where_values = array_merge( $where_values, array_fill( 0, 5, $search_term ) );
        }

        // Age filter
        if ( ! empty( $filters['age_min'] ) || ! empty( $filters['age_max'] ) ) {
            if ( ! empty( $filters['age_min'] ) ) {
                $where_clauses[] = "TIMESTAMPDIFF(YEAR, p.dob, CURDATE()) >= %d";
                $where_values[] = (int) $filters['age_min'];
            }
            if ( ! empty( $filters['age_max'] ) ) {
                $where_clauses[] = "TIMESTAMPDIFF(YEAR, p.dob, CURDATE()) <= %d";
                $where_values[] = (int) $filters['age_max'];
            }
        }

        // Gender filter
        if ( ! empty( $filters['gender'] ) ) {
            $where_clauses[] = "p.gender = %s";
            $where_values[] = $filters['gender'];
        }

        // Status filter
        if ( isset( $filters['status'] ) ) {
            $where_clauses[] = "p.status = %d";
            $where_values[] = $filters['status'];
        } else {
            $where_clauses[] = "p.status = 1"; // Active by default
        }

        $where_sql = implode( ' AND ', $where_clauses );

        $query = "SELECT p.*, 
                         COUNT(DISTINCT a.id) as appointment_count,
                         MAX(a.appointment_start_date) as last_visit
                  FROM {$wpdb->prefix}kc_patients p
                  LEFT JOIN {$wpdb->prefix}kc_appointments a ON p.id = a.patient_id
                  WHERE {$where_sql}
                  GROUP BY p.id
                  ORDER BY p.first_name, p.last_name
                  LIMIT 50";

        $results = $wpdb->get_results( $wpdb->prepare( $query, $where_values ), ARRAY_A );

        return array_map( function( $patient ) {
            $patient['id'] = (int) $patient['id'];
            $patient['appointment_count'] = (int) $patient['appointment_count'];
            $patient['age'] = $patient['dob'] ? self::calculate_age( $patient['dob'] ) : null;
            return $patient;
        }, $results );
    }

    /**
     * Get patient dashboard data
     *
     * @param int $patient_id Patient ID
     * @return array|WP_Error Dashboard data or error
     * @since 1.0.0
     */
    public static function get_patient_dashboard( $patient_id ) {
        $patient = Patient::get_by_id( $patient_id );
        
        if ( ! $patient ) {
            return new \WP_Error(
                'patient_not_found',
                'Patient not found',
                array( 'status' => 404 )
            );
        }

        // Permission check
        if ( ! Permission_Service::can_access_clinic( get_current_user_id(), $patient['clinic_id'] ) ) {
            return new \WP_Error(
                'access_denied',
                'You do not have access to this patient dashboard',
                array( 'status' => 403 )
            );
        }

        $dashboard = array();

        // Basic patient info
        $dashboard['patient'] = $patient;
        $dashboard['patient']['age'] = self::calculate_age( $patient['dob'] );

        // Recent activity
        $dashboard['recent_appointments'] = self::get_recent_appointments( $patient_id, 5 );
        $dashboard['recent_encounters'] = self::get_recent_encounters( $patient_id, 5 );
        $dashboard['active_prescriptions'] = self::get_active_prescriptions( $patient_id );

        // Medical summary
        $dashboard['medical_summary'] = self::get_medical_summary( $patient_id );

        // Upcoming appointments
        $dashboard['upcoming_appointments'] = self::get_upcoming_appointments( $patient_id );

        // Outstanding bills
        $dashboard['outstanding_bills'] = self::get_outstanding_bills( $patient_id );

        return $dashboard;
    }

    /**
     * Generate unique patient ID
     *
     * @param int $clinic_id Clinic ID
     * @return string Patient ID
     * @since 1.0.0
     */
    private static function generate_patient_id( $clinic_id ) {
        global $wpdb;

        $prefix = 'P' . str_pad( $clinic_id, 3, '0', STR_PAD_LEFT );
        
        // Get the highest existing patient ID for this clinic
        $max_id = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT MAX(CAST(SUBSTRING(patient_id, 5) AS UNSIGNED)) 
                 FROM {$wpdb->prefix}kc_patients 
                 WHERE clinic_id = %d AND patient_id LIKE %s",
                $clinic_id,
                $prefix . '%'
            )
        );

        $next_number = ( $max_id ? $max_id + 1 : 1 );
        
        return $prefix . str_pad( $next_number, 6, '0', STR_PAD_LEFT );
    }

    /**
     * Validate patient business rules
     *
     * @param array $patient_data Patient data
     * @param int   $clinic_id    Clinic ID
     * @param int   $patient_id   Patient ID (for updates)
     * @return bool|WP_Error True if valid, WP_Error otherwise
     * @since 1.0.0
     */
    private static function validate_patient_business_rules( $patient_data, $clinic_id, $patient_id = null ) {
        global $wpdb;

        $errors = array();

        // Check for duplicate patient ID in clinic
        if ( ! empty( $patient_data['patient_id'] ) ) {
            $existing_query = "SELECT id FROM {$wpdb->prefix}kc_patients WHERE patient_id = %s AND clinic_id = %d";
            $query_params = array( $patient_data['patient_id'], $clinic_id );

            if ( $patient_id ) {
                $existing_query .= " AND id != %d";
                $query_params[] = $patient_id;
            }

            $existing_patient = $wpdb->get_var( $wpdb->prepare( $existing_query, $query_params ) );
            
            if ( $existing_patient ) {
                $errors[] = 'A patient with this ID already exists in the clinic';
            }
        }

        // Validate contact information format
        if ( ! empty( $patient_data['contact_no'] ) ) {
            if ( ! preg_match( '/^[+]?[0-9\s\-\(\)]{7,20}$/', $patient_data['contact_no'] ) ) {
                $errors[] = 'Invalid contact number format';
            }
        }

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

        // Validate date of birth
        if ( ! empty( $patient_data['dob'] ) ) {
            $dob = strtotime( $patient_data['dob'] );
            if ( ! $dob || $dob > time() ) {
                $errors[] = 'Invalid date of birth';
            }
            
            // Check for reasonable age limits
            $age = self::calculate_age( $patient_data['dob'] );
            if ( $age > 150 ) {
                $errors[] = 'Date of birth indicates unrealistic age';
            }
        }

        // Validate gender
        if ( ! empty( $patient_data['gender'] ) ) {
            $valid_genders = array( 'male', 'female', 'other' );
            if ( ! in_array( strtolower( $patient_data['gender'] ), $valid_genders ) ) {
                $errors[] = 'Invalid gender value';
            }
        }

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

        return true;
    }

    /**
     * Setup patient defaults after creation
     *
     * @param int   $patient_id   Patient ID
     * @param array $patient_data Patient data
     * @since 1.0.0
     */
    private static function setup_patient_defaults( $patient_id, $patient_data ) {
        // Initialize medical history
        self::initialize_medical_history( $patient_id );

        // Setup default preferences
        self::setup_default_preferences( $patient_id );

        // Create patient folder structure (if needed)
        self::create_patient_folder_structure( $patient_id );
    }

    /**
     * Calculate age from date of birth
     *
     * @param string $dob Date of birth
     * @return int Age in years
     * @since 1.0.0
     */
    private static function calculate_age( $dob ) {
        if ( empty( $dob ) ) {
            return 0;
        }

        $birth_date = new \DateTime( $dob );
        $today = new \DateTime();
        
        return $birth_date->diff( $today )->y;
    }

    /**
     * Get patient appointments
     *
     * @param int $patient_id Patient ID
     * @param int $limit      Limit
     * @return array Appointments
     * @since 1.0.0
     */
    private static function get_patient_appointments( $patient_id, $limit = null ) {
        global $wpdb;

        $query = "SELECT a.*, d.display_name as doctor_name, c.name as clinic_name
                  FROM {$wpdb->prefix}kc_appointments a
                  LEFT JOIN {$wpdb->prefix}users d ON a.doctor_id = d.ID
                  LEFT JOIN {$wpdb->prefix}kc_clinics c ON a.clinic_id = c.id
                  WHERE a.patient_id = %d
                  ORDER BY a.appointment_start_date DESC";

        if ( $limit ) {
            $query .= " LIMIT {$limit}";
        }

        return $wpdb->get_results( $wpdb->prepare( $query, $patient_id ), ARRAY_A );
    }

    /**
     * Get patient encounters
     *
     * @param int $patient_id Patient ID
     * @param int $limit      Limit
     * @return array Encounters
     * @since 1.0.0
     */
    private static function get_patient_encounters( $patient_id, $limit = null ) {
        global $wpdb;

        $query = "SELECT e.*, d.display_name as doctor_name
                  FROM {$wpdb->prefix}kc_encounters e
                  LEFT JOIN {$wpdb->prefix}users d ON e.doctor_id = d.ID
                  WHERE e.patient_id = %d
                  ORDER BY e.encounter_date DESC";

        if ( $limit ) {
            $query .= " LIMIT {$limit}";
        }

        return $wpdb->get_results( $wpdb->prepare( $query, $patient_id ), ARRAY_A );
    }

    /**
     * Get patient prescriptions
     *
     * @param int $patient_id Patient ID
     * @return array Prescriptions
     * @since 1.0.0
     */
    private static function get_patient_prescriptions( $patient_id ) {
        global $wpdb;

        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT p.*, d.display_name as doctor_name
                 FROM {$wpdb->prefix}kc_prescriptions p
                 LEFT JOIN {$wpdb->prefix}users d ON p.doctor_id = d.ID
                 WHERE p.patient_id = %d
                 ORDER BY p.created_at DESC",
                $patient_id
            ),
            ARRAY_A
        );
    }

    /**
     * Get patient bills
     *
     * @param int $patient_id Patient ID
     * @return array Bills
     * @since 1.0.0
     */
    private static function get_patient_bills( $patient_id ) {
        global $wpdb;

        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}kc_bills 
                 WHERE patient_id = %d
                 ORDER BY created_at DESC",
                $patient_id
            ),
            ARRAY_A
        );
    }

    /**
     * Initialize medical history for patient
     *
     * @param int $patient_id Patient ID
     * @since 1.0.0
     */
    private static function initialize_medical_history( $patient_id ) {
        $default_history = array(
            'allergies' => array(),
            'medications' => array(),
            'conditions' => array(),
            'surgeries' => array(),
            'family_history' => array()
        );

        update_option( "kivicare_patient_{$patient_id}_medical_history", $default_history );
    }

    /**
     * Setup default preferences
     *
     * @param int $patient_id Patient ID
     * @since 1.0.0
     */
    private static function setup_default_preferences( $patient_id ) {
        $default_preferences = array(
            'appointment_reminders' => true,
            'email_notifications' => true,
            'sms_notifications' => false,
            'preferred_language' => 'en',
            'preferred_communication' => 'email'
        );

        update_option( "kivicare_patient_{$patient_id}_preferences", $default_preferences );
    }

    /**
     * Get patient medical history
     *
     * @param int $patient_id Patient ID
     * @return array Medical history
     * @since 1.0.0
     */
    private static function get_patient_medical_history( $patient_id ) {
        return get_option( "kivicare_patient_{$patient_id}_medical_history", array() );
    }

    /**
     * Get patient emergency contacts
     *
     * @param int $patient_id Patient ID
     * @return array Emergency contacts
     * @since 1.0.0
     */
    private static function get_patient_emergency_contacts( $patient_id ) {
        return get_option( "kivicare_patient_{$patient_id}_emergency_contacts", array() );
    }

    /**
     * Handle emergency contact changes
     *
     * @param int   $patient_id    Patient ID
     * @param array $current_data  Current patient data
     * @param array $new_data      New patient data
     * @since 1.0.0
     */
    private static function handle_emergency_contact_changes( $patient_id, $current_data, $new_data ) {
        // This would handle emergency contact updates
        // Implementation depends on how emergency contacts are stored
    }

    /**
     * Event handlers
     */
    public static function on_patient_created( $patient_id, $patient_data ) {
        error_log( "Care: New patient created - ID: {$patient_id}, Name: " . ( $patient_data['first_name'] ?? 'Unknown' ) );
    }

    public static function on_patient_updated( $patient_id, $patient_data ) {
        error_log( "Care: Patient updated - ID: {$patient_id}" );
        wp_cache_delete( "patient_{$patient_id}", 'kivicare' );
    }

    public static function on_patient_deleted( $patient_id ) {
        // Clean up related data
        delete_option( "kivicare_patient_{$patient_id}_medical_history" );
        delete_option( "kivicare_patient_{$patient_id}_preferences" );
        delete_option( "kivicare_patient_{$patient_id}_emergency_contacts" );

        wp_cache_delete( "patient_{$patient_id}", 'kivicare' );
        error_log( "Care: Patient deleted - ID: {$patient_id}" );
    }

    // Additional helper methods would be implemented here...
    private static function get_recent_appointments( $patient_id, $limit ) {
        return self::get_patient_appointments( $patient_id, $limit );
    }

    private static function get_recent_encounters( $patient_id, $limit ) {
        return self::get_patient_encounters( $patient_id, $limit );
    }

    private static function get_active_prescriptions( $patient_id ) {
        global $wpdb;
        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}kc_prescriptions 
                 WHERE patient_id = %d AND status = 'active'
                 ORDER BY created_at DESC",
                $patient_id
            ),
            ARRAY_A
        );
    }

    private static function get_medical_summary( $patient_id ) {
        return array(
            'medical_history' => self::get_patient_medical_history( $patient_id ),
            'last_visit' => self::get_last_visit_date( $patient_id ),
            'chronic_conditions' => self::get_chronic_conditions( $patient_id ),
            'active_medications' => self::get_active_medications( $patient_id )
        );
    }

    private static function get_upcoming_appointments( $patient_id ) {
        global $wpdb;
        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT a.*, d.display_name as doctor_name
                 FROM {$wpdb->prefix}kc_appointments a
                 LEFT JOIN {$wpdb->prefix}users d ON a.doctor_id = d.ID
                 WHERE a.patient_id = %d AND a.appointment_start_date > NOW()
                 ORDER BY a.appointment_start_date ASC
                 LIMIT 5",
                $patient_id
            ),
            ARRAY_A
        );
    }

    private static function get_outstanding_bills( $patient_id ) {
        global $wpdb;
        return $wpdb->get_results(
            $wpdb->prepare(
                "SELECT * FROM {$wpdb->prefix}kc_bills 
                 WHERE patient_id = %d AND status = 'pending'
                 ORDER BY created_at DESC",
                $patient_id
            ),
            ARRAY_A
        );
    }

    private static function get_last_visit_date( $patient_id ) {
        global $wpdb;
        return $wpdb->get_var(
            $wpdb->prepare(
                "SELECT MAX(appointment_start_date) FROM {$wpdb->prefix}kc_appointments 
                 WHERE patient_id = %d AND status = 2",
                $patient_id
            )
        );
    }

    private static function get_chronic_conditions( $patient_id ) {
        $medical_history = self::get_patient_medical_history( $patient_id );
        return isset( $medical_history['conditions'] ) ? 
            array_filter( $medical_history['conditions'], function( $condition ) {
                return isset( $condition['chronic'] ) && $condition['chronic'];
            } ) : array();
    }

    private static function get_active_medications( $patient_id ) {
        $medical_history = self::get_patient_medical_history( $patient_id );
        return isset( $medical_history['medications'] ) ? 
            array_filter( $medical_history['medications'], function( $medication ) {
                return isset( $medication['active'] ) && $medication['active'];
            } ) : array();
    }

    private static function create_patient_folder_structure( $patient_id ) {
        // Implementation for creating patient document folders if needed
        // This would depend on the file management system
    }
}