<?php
/**
 * Encounter Model
 *
 * Handles medical encounter operations and patient consultation data
 *
 * @package Care_API
 * @subpackage Models
 * @version    1.0.0
 * @author     Descomplicar® <dev@descomplicar.pt>
 * @link       https://descomplicar.pt
 * @since      1.0.0
 */

namespace Care_API\Models;

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

/**
 * Class Encounter
 *
 * Model for handling patient encounters (medical consultations)
 *
 * @since 1.0.0
 */
class Encounter {

    /**
     * Database table name
     *
     * @var string
     */
    private static $table_name = 'kc_patient_encounters';

    /**
     * Encounter ID
     *
     * @var int
     */
    public $id;

    /**
     * Encounter data
     *
     * @var array
     */
    private $data = array();

    /**
     * Required fields for encounter creation
     *
     * @var array
     */
    private static $required_fields = array(
        'encounter_date',
        'clinic_id',
        'doctor_id',
        'patient_id'
    );

    /**
     * Valid encounter statuses
     *
     * @var array
     */
    private static $valid_statuses = array(
        0 => 'draft',
        1 => 'completed',
        2 => 'cancelled'
    );

    /**
     * Constructor
     *
     * @param int|array $encounter_id_or_data Encounter ID or data array
     * @since 1.0.0
     */
    public function __construct( $encounter_id_or_data = null ) {
        if ( is_numeric( $encounter_id_or_data ) ) {
            $this->id = (int) $encounter_id_or_data;
            $this->load_data();
        } elseif ( is_array( $encounter_id_or_data ) ) {
            $this->data = $encounter_id_or_data;
            $this->id = isset( $this->data['id'] ) ? (int) $this->data['id'] : null;
        }
    }

    /**
     * Load encounter data from database
     *
     * @return bool True on success, false on failure
     * @since 1.0.0
     */
    private function load_data() {
        if ( ! $this->id ) {
            return false;
        }

        $encounter_data = self::get_encounter_full_data( $this->id );
        
        if ( $encounter_data ) {
            $this->data = $encounter_data;
            return true;
        }

        return false;
    }

    /**
     * Create a new encounter
     *
     * @param array $encounter_data Encounter data
     * @return int|WP_Error Encounter ID on success, WP_Error on failure
     * @since 1.0.0
     */
    public static function create( $encounter_data ) {
        // Validate required fields
        $validation = self::validate_encounter_data( $encounter_data );
        if ( is_wp_error( $validation ) ) {
            return $validation;
        }

        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        // Prepare data for insertion
        $insert_data = array(
            'encounter_date' => sanitize_text_field( $encounter_data['encounter_date'] ),
            'clinic_id' => (int) $encounter_data['clinic_id'],
            'doctor_id' => (int) $encounter_data['doctor_id'],
            'patient_id' => (int) $encounter_data['patient_id'],
            'appointment_id' => isset( $encounter_data['appointment_id'] ) ? (int) $encounter_data['appointment_id'] : null,
            'description' => isset( $encounter_data['description'] ) ? sanitize_textarea_field( $encounter_data['description'] ) : '',
            'status' => isset( $encounter_data['status'] ) ? (int) $encounter_data['status'] : 0,
            'added_by' => get_current_user_id(),
            'created_at' => current_time( 'mysql' ),
            'template_id' => isset( $encounter_data['template_id'] ) ? (int) $encounter_data['template_id'] : null
        );

        $result = $wpdb->insert( $table, $insert_data );

        if ( $result === false ) {
            return new \WP_Error(
                'encounter_creation_failed',
                'Failed to create encounter: ' . $wpdb->last_error,
                array( 'status' => 500 )
            );
        }

        $encounter_id = $wpdb->insert_id;

        // Create medical history entries if provided
        if ( ! empty( $encounter_data['medical_history'] ) && is_array( $encounter_data['medical_history'] ) ) {
            self::create_medical_history_entries( $encounter_id, $encounter_data['medical_history'] );
        }

        return $encounter_id;
    }

    /**
     * Update encounter data
     *
     * @param int   $encounter_id Encounter ID
     * @param array $encounter_data Updated encounter data
     * @return bool|WP_Error True on success, WP_Error on failure
     * @since 1.0.0
     */
    public static function update( $encounter_id, $encounter_data ) {
        if ( ! self::exists( $encounter_id ) ) {
            return new \WP_Error(
                'encounter_not_found',
                'Encounter not found',
                array( 'status' => 404 )
            );
        }

        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        // Prepare update data
        $update_data = array();
        $allowed_fields = array(
            'encounter_date', 'clinic_id', 'doctor_id', 'patient_id',
            'appointment_id', 'description', 'status', 'template_id'
        );

        foreach ( $allowed_fields as $field ) {
            if ( isset( $encounter_data[ $field ] ) ) {
                $value = $encounter_data[ $field ];
                
                switch ( $field ) {
                    case 'clinic_id':
                    case 'doctor_id':
                    case 'patient_id':
                    case 'appointment_id':
                    case 'status':
                    case 'template_id':
                        $update_data[ $field ] = (int) $value;
                        break;
                    case 'description':
                        $update_data[ $field ] = sanitize_textarea_field( $value );
                        break;
                    default:
                        $update_data[ $field ] = sanitize_text_field( $value );
                }
            }
        }

        if ( empty( $update_data ) ) {
            return new \WP_Error(
                'no_data_to_update',
                'No valid data provided for update',
                array( 'status' => 400 )
            );
        }

        $result = $wpdb->update(
            $table,
            $update_data,
            array( 'id' => $encounter_id ),
            null,
            array( '%d' )
        );

        if ( $result === false ) {
            return new \WP_Error(
                'encounter_update_failed',
                'Failed to update encounter: ' . $wpdb->last_error,
                array( 'status' => 500 )
            );
        }

        return true;
    }

    /**
     * Delete an encounter
     *
     * @param int $encounter_id Encounter ID
     * @return bool|WP_Error True on success, WP_Error on failure
     * @since 1.0.0
     */
    public static function delete( $encounter_id ) {
        if ( ! self::exists( $encounter_id ) ) {
            return new \WP_Error(
                'encounter_not_found',
                'Encounter not found',
                array( 'status' => 404 )
            );
        }

        // Check if encounter can be deleted (has prescriptions or bills)
        if ( self::has_dependencies( $encounter_id ) ) {
            return new \WP_Error(
                'encounter_has_dependencies',
                'Cannot delete encounter with associated prescriptions or bills',
                array( 'status' => 409 )
            );
        }

        global $wpdb;

        // Delete medical history entries first
        $wpdb->delete(
            "{$wpdb->prefix}kc_medical_history",
            array( 'encounter_id' => $encounter_id ),
            array( '%d' )
        );

        // Delete encounter
        $table = $wpdb->prefix . self::$table_name;
        $result = $wpdb->delete(
            $table,
            array( 'id' => $encounter_id ),
            array( '%d' )
        );

        if ( $result === false ) {
            return new \WP_Error(
                'encounter_deletion_failed',
                'Failed to delete encounter: ' . $wpdb->last_error,
                array( 'status' => 500 )
            );
        }

        return true;
    }

    /**
     * Get encounter by ID
     *
     * @param int $encounter_id Encounter ID
     * @return array|null Encounter data or null if not found
     * @since 1.0.0
     */
    public static function get_by_id( $encounter_id ) {
        return self::get_encounter_full_data( $encounter_id );
    }

    /**
     * Get all encounters with optional filtering
     *
     * @param array $args Query arguments
     * @return array Array of encounter data
     * @since 1.0.0
     */
    public static function get_all( $args = array() ) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        $defaults = array(
            'clinic_id' => null,
            'doctor_id' => null,
            'patient_id' => null,
            'status' => null,
            'date_from' => null,
            'date_to' => null,
            'search' => '',
            'limit' => 50,
            'offset' => 0,
            'orderby' => 'encounter_date',
            'order' => 'DESC'
        );

        $args = wp_parse_args( $args, $defaults );

        $where_clauses = array( '1=1' );
        $where_values = array();

        // Clinic filter
        if ( ! is_null( $args['clinic_id'] ) ) {
            $where_clauses[] = 'e.clinic_id = %d';
            $where_values[] = $args['clinic_id'];
        }

        // Doctor filter
        if ( ! is_null( $args['doctor_id'] ) ) {
            $where_clauses[] = 'e.doctor_id = %d';
            $where_values[] = $args['doctor_id'];
        }

        // Patient filter
        if ( ! is_null( $args['patient_id'] ) ) {
            $where_clauses[] = 'e.patient_id = %d';
            $where_values[] = $args['patient_id'];
        }

        // Status filter
        if ( ! is_null( $args['status'] ) ) {
            $where_clauses[] = 'e.status = %d';
            $where_values[] = $args['status'];
        }

        // Date range filters
        if ( ! is_null( $args['date_from'] ) ) {
            $where_clauses[] = 'e.encounter_date >= %s';
            $where_values[] = $args['date_from'];
        }

        if ( ! is_null( $args['date_to'] ) ) {
            $where_clauses[] = 'e.encounter_date <= %s';
            $where_values[] = $args['date_to'];
        }

        // Search filter
        if ( ! empty( $args['search'] ) ) {
            $where_clauses[] = '(p.first_name LIKE %s OR p.last_name LIKE %s OR d.first_name LIKE %s OR d.last_name LIKE %s OR e.description LIKE %s)';
            $search_term = '%' . $wpdb->esc_like( $args['search'] ) . '%';
            $where_values = array_merge( $where_values, array_fill( 0, 5, $search_term ) );
        }

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

        // Whitelist for orderby
        $allowed_orderby = array( 'encounter_date', 'patient_name', 'doctor_name', 'clinic_name', 'status' );
        $orderby = in_array( $args['orderby'], $allowed_orderby, true ) ? $args['orderby'] : 'encounter_date';
        
        // Whitelist for order
        $order = in_array( strtoupper( $args['order'] ), array( 'ASC', 'DESC' ), true ) ? strtoupper( $args['order'] ) : 'DESC';

        // Build query
        $query = "SELECT e.*, 
                         c.name as clinic_name,
                         CONCAT(p.first_name, ' ', p.last_name) as patient_name,
                         p.user_email as patient_email,
                         CONCAT(d.first_name, ' ', d.last_name) as doctor_name,
                         d.user_email as doctor_email,
                         CONCAT(ab.first_name, ' ', ab.last_name) as added_by_name
                  FROM {$table} e
                  LEFT JOIN {$wpdb->prefix}kc_clinics c ON e.clinic_id = c.id
                  LEFT JOIN {$wpdb->prefix}users p ON e.patient_id = p.ID
                  LEFT JOIN {$wpdb->prefix}users d ON e.doctor_id = d.ID
                  LEFT JOIN {$wpdb->prefix}users ab ON e.added_by = ab.ID
                  WHERE {$where_sql}
                  ORDER BY {$orderby} {$order}
                  LIMIT %d OFFSET %d";
        
        $safe_query = $wpdb->prepare(
            $query,
            array_merge(
                $where_values,
                array( $args['limit'], $args['offset'] )
            )
        );

        $encounters = $wpdb->get_results( $safe_query, ARRAY_A );

        return array_map( array( self::class, 'format_encounter_data' ), $encounters );
    }

    /**
     * Get encounter full data with related entities
     *
     * @param int $encounter_id Encounter ID
     * @return array|null Full encounter data or null if not found
     * @since 1.0.0
     */
    public static function get_encounter_full_data( $encounter_id ) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        $encounter = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT e.*, 
                        c.name as clinic_name, c.address as clinic_address,
                        CONCAT(p.first_name, ' ', p.last_name) as patient_name,
                        p.user_email as patient_email,
                        CONCAT(d.first_name, ' ', d.last_name) as doctor_name,
                        d.user_email as doctor_email,
                        CONCAT(ab.first_name, ' ', ab.last_name) as added_by_name
                 FROM {$table} e
                 LEFT JOIN {$wpdb->prefix}kc_clinics c ON e.clinic_id = c.id
                 LEFT JOIN {$wpdb->prefix}users p ON e.patient_id = p.ID
                 LEFT JOIN {$wpdb->prefix}users d ON e.doctor_id = d.ID
                 LEFT JOIN {$wpdb->prefix}users ab ON e.added_by = ab.ID
                 WHERE e.id = %d",
                $encounter_id
            ),
            ARRAY_A
        );

        if ( ! $encounter ) {
            return null;
        }

        return self::format_encounter_data( $encounter );
    }

    /**
     * Get encounter prescriptions
     *
     * @param int $encounter_id Encounter ID
     * @return array Array of prescriptions
     * @since 1.0.0
     */
    public static function get_prescriptions( $encounter_id ) {
        global $wpdb;

        $prescriptions = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT p.*, 
                        CONCAT(ab.first_name, ' ', ab.last_name) as added_by_name
                 FROM {$wpdb->prefix}kc_prescription p
                 LEFT JOIN {$wpdb->prefix}users ab ON p.added_by = ab.ID
                 WHERE p.encounter_id = %d
                 ORDER BY p.created_at ASC",
                $encounter_id
            ),
            ARRAY_A
        );

        return array_map( function( $prescription ) {
            return array(
                'id' => (int) $prescription['id'],
                'name' => $prescription['name'],
                'frequency' => $prescription['frequency'],
                'duration' => $prescription['duration'],
                'instruction' => $prescription['instruction'],
                'patient_id' => (int) $prescription['patient_id'],
                'added_by' => (int) $prescription['added_by'],
                'added_by_name' => $prescription['added_by_name'],
                'created_at' => $prescription['created_at'],
                'is_from_template' => (bool) $prescription['is_from_template']
            );
        }, $prescriptions );
    }

    /**
     * Get encounter medical history
     *
     * @param int $encounter_id Encounter ID
     * @return array Array of medical history entries
     * @since 1.0.0
     */
    public static function get_medical_history( $encounter_id ) {
        global $wpdb;

        $history = $wpdb->get_results(
            $wpdb->prepare(
                "SELECT mh.*, 
                        CONCAT(ab.first_name, ' ', ab.last_name) as added_by_name
                 FROM {$wpdb->prefix}kc_medical_history mh
                 LEFT JOIN {$wpdb->prefix}users ab ON mh.added_by = ab.ID
                 WHERE mh.encounter_id = %d
                 ORDER BY mh.created_at ASC",
                $encounter_id
            ),
            ARRAY_A
        );

        return array_map( function( $entry ) {
            return array(
                'id' => (int) $entry['id'],
                'type' => $entry['type'],
                'title' => $entry['title'],
                'patient_id' => (int) $entry['patient_id'],
                'added_by' => (int) $entry['added_by'],
                'added_by_name' => $entry['added_by_name'],
                'created_at' => $entry['created_at']
            );
        }, $history );
    }

    /**
     * Get encounter bills
     *
     * @param int $encounter_id Encounter ID
     * @return array Array of bills
     * @since 1.0.0
     */
    public static function get_bills( $encounter_id ) {
        global $wpdb;

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

        return array_map( function( $bill ) {
            return array(
                'id' => (int) $bill['id'],
                'title' => $bill['title'],
                'total_amount' => (float) $bill['total_amount'],
                'discount' => (float) $bill['discount'],
                'actual_amount' => (float) $bill['actual_amount'],
                'status' => (int) $bill['status'],
                'payment_status' => $bill['payment_status'],
                'created_at' => $bill['created_at'],
                'clinic_id' => (int) $bill['clinic_id'],
                'appointment_id' => (int) $bill['appointment_id']
            );
        }, $bills );
    }

    /**
     * Add prescription to encounter
     *
     * @param int   $encounter_id      Encounter ID
     * @param array $prescription_data Prescription data
     * @return int|WP_Error Prescription ID on success, WP_Error on failure
     * @since 1.0.0
     */
    public static function add_prescription( $encounter_id, $prescription_data ) {
        if ( ! self::exists( $encounter_id ) ) {
            return new \WP_Error(
                'encounter_not_found',
                'Encounter not found',
                array( 'status' => 404 )
            );
        }

        $encounter = self::get_by_id( $encounter_id );
        
        return Prescription::create( array_merge( $prescription_data, array(
            'encounter_id' => $encounter_id,
            'patient_id' => $encounter['patient']['id']
        ) ) );
    }

    /**
     * Check if encounter exists
     *
     * @param int $encounter_id Encounter ID
     * @return bool True if exists, false otherwise
     * @since 1.0.0
     */
    public static function exists( $encounter_id ) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        $count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$table} WHERE id = %d",
                $encounter_id
            )
        );

        return (int) $count > 0;
    }

    /**
     * Check if encounter has dependencies (prescriptions, bills, etc.)
     *
     * @param int $encounter_id Encounter ID
     * @return bool True if has dependencies, false otherwise
     * @since 1.0.0
     */
    private static function has_dependencies( $encounter_id ) {
        global $wpdb;

        // Check prescriptions
        $prescriptions_count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_prescription WHERE encounter_id = %d",
                $encounter_id
            )
        );

        if ( (int) $prescriptions_count > 0 ) {
            return true;
        }

        // Check bills
        $bills_count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_bills WHERE encounter_id = %d",
                $encounter_id
            )
        );

        return (int) $bills_count > 0;
    }

    /**
     * Validate encounter data
     *
     * @param array $encounter_data Encounter data to validate
     * @return bool|WP_Error True if valid, WP_Error if invalid
     * @since 1.0.0
     */
    private static function validate_encounter_data( $encounter_data ) {
        $errors = array();

        // Check required fields
        foreach ( self::$required_fields as $field ) {
            if ( empty( $encounter_data[ $field ] ) ) {
                $errors[] = "Field '{$field}' is required";
            }
        }

        // Validate date format
        if ( ! empty( $encounter_data['encounter_date'] ) ) {
            $date = \DateTime::createFromFormat( 'Y-m-d', $encounter_data['encounter_date'] );
            if ( ! $date || $date->format( 'Y-m-d' ) !== $encounter_data['encounter_date'] ) {
                $errors[] = 'Invalid encounter date format. Use YYYY-MM-DD';
            }
        }

        // Validate entities exist
        if ( ! empty( $encounter_data['clinic_id'] ) && 
             ! Clinic::exists( $encounter_data['clinic_id'] ) ) {
            $errors[] = 'Clinic not found';
        }

        if ( ! empty( $encounter_data['doctor_id'] ) && 
             ! Doctor::exists( $encounter_data['doctor_id'] ) ) {
            $errors[] = 'Doctor not found';
        }

        if ( ! empty( $encounter_data['patient_id'] ) && 
             ! Patient::exists( $encounter_data['patient_id'] ) ) {
            $errors[] = 'Patient not found';
        }

        // Validate appointment exists if provided
        if ( ! empty( $encounter_data['appointment_id'] ) && 
             ! Appointment::exists( $encounter_data['appointment_id'] ) ) {
            $errors[] = 'Appointment not found';
        }

        // Validate status
        if ( isset( $encounter_data['status'] ) && 
             ! array_key_exists( $encounter_data['status'], self::$valid_statuses ) ) {
            $errors[] = 'Invalid status value';
        }

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

        return true;
    }

    /**
     * Format encounter data for API response
     *
     * @param array $encounter_data Raw encounter data
     * @return array Formatted encounter data
     * @since 1.0.0
     */
    private static function format_encounter_data( $encounter_data ) {
        if ( ! $encounter_data ) {
            return null;
        }

        $formatted = array(
            'id' => (int) $encounter_data['id'],
            'encounter_date' => $encounter_data['encounter_date'],
            'description' => $encounter_data['description'],
            'status' => (int) $encounter_data['status'],
            'status_text' => self::$valid_statuses[ $encounter_data['status'] ] ?? 'unknown',
            'created_at' => $encounter_data['created_at'],
            'clinic' => array(
                'id' => (int) $encounter_data['clinic_id'],
                'name' => $encounter_data['clinic_name'] ?? '',
                'address' => $encounter_data['clinic_address'] ?? ''
            ),
            'patient' => array(
                'id' => (int) $encounter_data['patient_id'],
                'name' => $encounter_data['patient_name'] ?? '',
                'email' => $encounter_data['patient_email'] ?? ''
            ),
            'doctor' => array(
                'id' => (int) $encounter_data['doctor_id'],
                'name' => $encounter_data['doctor_name'] ?? '',
                'email' => $encounter_data['doctor_email'] ?? ''
            ),
            'appointment_id' => isset( $encounter_data['appointment_id'] ) ? (int) $encounter_data['appointment_id'] : null,
            'template_id' => isset( $encounter_data['template_id'] ) ? (int) $encounter_data['template_id'] : null,
            'added_by' => array(
                'id' => (int) $encounter_data['added_by'],
                'name' => $encounter_data['added_by_name'] ?? ''
            )
        );

        return $formatted;
    }

    /**
     * Create medical history entries for encounter
     *
     * @param int   $encounter_id Encounter ID
     * @param array $history_entries Array of history entries
     * @return bool True on success
     * @since 1.0.0
     */
    private static function create_medical_history_entries( $encounter_id, $history_entries ) {
        global $wpdb;
        
        $encounter = self::get_by_id( $encounter_id );
        if ( ! $encounter ) {
            return false;
        }

        foreach ( $history_entries as $entry ) {
            $wpdb->insert(
                "{$wpdb->prefix}kc_medical_history",
                array(
                    'encounter_id' => $encounter_id,
                    'patient_id' => $encounter['patient']['id'],
                    'type' => sanitize_text_field( $entry['type'] ),
                    'title' => sanitize_text_field( $entry['title'] ),
                    'added_by' => get_current_user_id(),
                    'created_at' => current_time( 'mysql' )
                ),
                array( '%d', '%d', '%s', '%s', '%d', '%s' )
            );
        }

        return true;
    }

    /**
     * Get encounter statistics
     *
     * @param array $filters Optional filters
     * @return array Encounter statistics
     * @since 1.0.0
     */
    public static function get_statistics( $filters = array() ) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        $where_clauses = array( '1=1' );
        $where_values = array();

        if ( ! empty( $filters['clinic_id'] ) ) {
            $where_clauses[] = 'clinic_id = %d';
            $where_values[] = $filters['clinic_id'];
        }

        if ( ! empty( $filters['doctor_id'] ) ) {
            $where_clauses[] = 'doctor_id = %d';
            $where_values[] = $filters['doctor_id'];
        }

        if ( ! empty( $filters['patient_id'] ) ) {
            $where_clauses[] = 'patient_id = %d';
            $where_values[] = $filters['patient_id'];
        }

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

        $stats = array(
            'total_encounters' => 0,
            'draft_encounters' => 0,
            'completed_encounters' => 0,
            'cancelled_encounters' => 0,
            'encounters_today' => 0,
            'encounters_this_week' => 0,
            'encounters_this_month' => 0,
            'avg_encounters_per_day' => 0
        );

        // Total encounters
        $query = "SELECT COUNT(*) FROM {$table} WHERE {$where_sql}";
        $stats['total_encounters'] = (int) $wpdb->get_var( $wpdb->prepare( $query, $where_values ) );

        // Encounters by status
        foreach ( self::$valid_statuses as $status_id => $status_name ) {
            $status_where_sql = $where_sql . ' AND status = %d';
            $query = "SELECT COUNT(*) FROM {$table} WHERE {$status_where_sql}";
            $stats[ $status_name . '_encounters' ] = (int) $wpdb->get_var( $wpdb->prepare( $query, array_merge( $where_values, array( $status_id ) ) ) );
        }

        // Encounters today
        $today_where_sql = $where_sql . ' AND encounter_date = CURDATE()';
        $query = "SELECT COUNT(*) FROM {$table} WHERE {$today_where_sql}";
        $stats['encounters_today'] = (int) $wpdb->get_var( $wpdb->prepare( $query, $where_values ) );

        // Encounters this week
        $week_where_sql = $where_sql . ' AND WEEK(encounter_date) = WEEK(CURDATE()) AND YEAR(encounter_date) = YEAR(CURDATE())';
        $query = "SELECT COUNT(*) FROM {$table} WHERE {$week_where_sql}";
        $stats['encounters_this_week'] = (int) $wpdb->get_var( $wpdb->prepare( $query, $where_values ) );

        // Encounters this month
        $month_where_sql = $where_sql . ' AND MONTH(encounter_date) = MONTH(CURDATE()) AND YEAR(encounter_date) = YEAR(CURDATE())';
        $query = "SELECT COUNT(*) FROM {$table} WHERE {$month_where_sql}";
        $stats['encounters_this_month'] = (int) $wpdb->get_var( $wpdb->prepare( $query, $where_values ) );

        // Calculate average encounters per day (last 30 days)
        if ( $stats['total_encounters'] > 0 ) {
            $days_active = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT DATEDIFF(MAX(encounter_date), MIN(encounter_date)) + 1 
                     FROM {$table} 
                     WHERE encounter_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND {$where_sql}",
                    $where_values
                )
            );
            
            if ( $days_active > 0 ) {
                $encounters_last_30_days_query = "SELECT COUNT(*) FROM {$table} WHERE encounter_date >= DATE_SUB(CURDATE(), INTERVAL 30 DAY) AND {$where_sql}";
                $encounters_last_30_days = (int) $wpdb->get_var( $wpdb->prepare( $encounters_last_30_days_query, $where_values ) );
                $stats['avg_encounters_per_day'] = round( $encounters_last_30_days / min( (int)$days_active, 30 ), 2 );
            }
        }

        return $stats;
    }

    /**
     * Get encounters by patient
     *
     * @param int $patient_id Patient user ID
     * @param array $args Query arguments
     * @return array Array of encounter data
     * @since 1.0.0
     */
    public static function get_by_patient( $patient_id, $args = array() ) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        $defaults = array(
            'clinic_id' => null,
            'doctor_id' => null,
            'status' => null,
            'limit' => 50,
            'offset' => 0,
            'orderby' => 'encounter_date',
            'order' => 'DESC'
        );

        $args = wp_parse_args( $args, $defaults );

        $where_clauses = array( 'e.patient_id = %d' );
        $where_values = array( $patient_id );

        // Add filters
        if ( ! is_null( $args['clinic_id'] ) ) {
            $where_clauses[] = 'e.clinic_id = %d';
            $where_values[] = $args['clinic_id'];
        }

        if ( ! is_null( $args['doctor_id'] ) ) {
            $where_clauses[] = 'e.doctor_id = %d';
            $where_values[] = $args['doctor_id'];
        }

        if ( ! is_null( $args['status'] ) ) {
            $where_clauses[] = 'e.status = %d';
            $where_values[] = $args['status'];
        }

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

        // Whitelist for orderby
        $allowed_orderby = array( 'encounter_date', 'clinic_name', 'doctor_name', 'status' );
        $orderby = in_array( $args['orderby'], $allowed_orderby, true ) ? 'e.' . $args['orderby'] : 'e.encounter_date';

        // Whitelist for order
        $order = in_array( strtoupper( $args['order'] ), array( 'ASC', 'DESC' ), true ) ? strtoupper( $args['order'] ) : 'DESC';

        $query = $wpdb->prepare(
            "SELECT e.*, 
                    c.name as clinic_name,
                    CONCAT(du.first_name, ' ', du.last_name) as doctor_name,
                    CONCAT(pu.first_name, ' ', pu.last_name) as patient_name,
                    a.appointment_start_date, a.appointment_start_time
             FROM {$table} e
             LEFT JOIN {$wpdb->prefix}kc_clinics c ON e.clinic_id = c.id
             LEFT JOIN {$wpdb->prefix}users du ON e.doctor_id = du.ID
             LEFT JOIN {$wpdb->prefix}users pu ON e.patient_id = pu.ID
             LEFT JOIN {$wpdb->prefix}kc_appointments a ON e.appointment_id = a.id
             WHERE {$where_sql}
             ORDER BY {$orderby} {$order}
             LIMIT %d OFFSET %d",
            array_merge( $where_values, array( $args['limit'], $args['offset'] ) )
        );

        $encounters = $wpdb->get_results( $query, ARRAY_A );

        return array_map( array( self::class, 'format_encounter_data' ), $encounters );
    }

    /**
     * Get encounters by doctor
     *
     * @param int $doctor_id Doctor user ID
     * @param array $args Query arguments
     * @return array Array of encounter data
     * @since 1.0.0
     */
    public static function get_by_doctor( $doctor_id, $args = array() ) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        $defaults = array(
            'clinic_id' => null,
            'patient_id' => null,
            'status' => null,
            'date_from' => null,
            'date_to' => null,
            'limit' => 50,
            'offset' => 0,
            'orderby' => 'encounter_date',
            'order' => 'DESC'
        );

        $args = wp_parse_args( $args, $defaults );

        $where_clauses = array( 'e.doctor_id = %d' );
        $where_values = array( $doctor_id );

        // Add filters
        if ( ! is_null( $args['clinic_id'] ) ) {
            $where_clauses[] = 'e.clinic_id = %d';
            $where_values[] = $args['clinic_id'];
        }

        if ( ! is_null( $args['patient_id'] ) ) {
            $where_clauses[] = 'e.patient_id = %d';
            $where_values[] = $args['patient_id'];
        }

        if ( ! is_null( $args['status'] ) ) {
            $where_clauses[] = 'e.status = %d';
            $where_values[] = $args['status'];
        }

        if ( ! is_null( $args['date_from'] ) ) {
            $where_clauses[] = 'e.encounter_date >= %s';
            $where_values[] = $args['date_from'];
        }

        if ( ! is_null( $args['date_to'] ) ) {
            $where_clauses[] = 'e.encounter_date <= %s';
            $where_values[] = $args['date_to'];
        }

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

        // Whitelist for orderby
        $allowed_orderby = array( 'encounter_date', 'clinic_name', 'patient_name', 'status' );
        $orderby = in_array( $args['orderby'], $allowed_orderby, true ) ? 'e.' . $args['orderby'] : 'e.encounter_date';

        // Whitelist for order
        $order = in_array( strtoupper( $args['order'] ), array( 'ASC', 'DESC' ), true ) ? strtoupper( $args['order'] ) : 'DESC';

        $query = $wpdb->prepare(
            "SELECT e.*, 
                    c.name as clinic_name,
                    CONCAT(du.first_name, ' ', du.last_name) as doctor_name,
                    CONCAT(pu.first_name, ' ', pu.last_name) as patient_name,
                    a.appointment_start_date, a.appointment_start_time
             FROM {$table} e
             LEFT JOIN {$wpdb->prefix}kc_clinics c ON e.clinic_id = c.id
             LEFT JOIN {$wpdb->prefix}users du ON e.doctor_id = du.ID
             LEFT JOIN {$wpdb->prefix}users pu ON e.patient_id = pu.ID
             LEFT JOIN {$wpdb->prefix}kc_appointments a ON e.appointment_id = a.id
             WHERE {$where_sql}
             ORDER BY {$orderby} {$order}
             LIMIT %d OFFSET %d",
            array_merge( $where_values, array( $args['limit'], $args['offset'] ) )
        );

        $encounters = $wpdb->get_results( $query, ARRAY_A );

        return array_map( array( self::class, 'format_encounter_data' ), $encounters );
    }
}