<?php
/**
 * Clinic Model
 *
 * Handles clinic entity operations and business logic
 *
 * @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 Clinic
 *
 * Model for handling clinic data and operations
 *
 * @since 1.0.0
 */
class Clinic {

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

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

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

    /**
     * Required fields for clinic creation
     *
     * @var array
     */
    private static $required_fields = array(
        'name',
        'email',
        'telephone_no',
        'address',
        'city',
        'state',
        'country',
        'postal_code'
    );

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

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

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

        $clinic_data = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$table} WHERE id = %d",
                $this->id
            ),
            ARRAY_A
        );

        if ( $clinic_data ) {
            $this->data = $clinic_data;
            return true;
        }

        return false;
    }

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

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

        // Prepare data for insertion
        $insert_data = array(
            'name' => sanitize_text_field( $clinic_data['name'] ),
            'email' => sanitize_email( $clinic_data['email'] ),
            'telephone_no' => sanitize_text_field( $clinic_data['telephone_no'] ),
            'specialties' => isset( $clinic_data['specialties'] ) ? wp_json_encode( $clinic_data['specialties'] ) : '',
            'address' => sanitize_textarea_field( $clinic_data['address'] ),
            'city' => sanitize_text_field( $clinic_data['city'] ),
            'state' => sanitize_text_field( $clinic_data['state'] ),
            'country' => sanitize_text_field( $clinic_data['country'] ),
            'postal_code' => sanitize_text_field( $clinic_data['postal_code'] ),
            'status' => isset( $clinic_data['status'] ) ? (int) $clinic_data['status'] : 1,
            'clinic_admin_id' => isset( $clinic_data['clinic_admin_id'] ) ? (int) $clinic_data['clinic_admin_id'] : null,
            'clinic_logo' => isset( $clinic_data['clinic_logo'] ) ? (int) $clinic_data['clinic_logo'] : null,
            'profile_image' => isset( $clinic_data['profile_image'] ) ? (int) $clinic_data['profile_image'] : null,
            'extra' => isset( $clinic_data['extra'] ) ? wp_json_encode( $clinic_data['extra'] ) : '',
            'created_at' => current_time( 'mysql' )
        );

        $insert_data = array_map( array( self::class, 'prepare_for_db' ), $insert_data );

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

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

        return $wpdb->insert_id;
    }

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

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

        // Prepare update data
        $update_data = array();
        $allowed_fields = array(
            'name', 'email', 'telephone_no', 'specialties', 'address',
            'city', 'state', 'country', 'postal_code', 'status',
            'clinic_admin_id', 'clinic_logo', 'profile_image', 'extra'
        );

        foreach ( $allowed_fields as $field ) {
            if ( isset( $clinic_data[ $field ] ) ) {
                $value = $clinic_data[ $field ];
                
                switch ( $field ) {
                    case 'email':
                        $update_data[ $field ] = sanitize_email( $value );
                        break;
                    case 'specialties':
                    case 'extra':
                        $update_data[ $field ] = is_array( $value ) ? wp_json_encode( $value ) : $value;
                        break;
                    case 'status':
                    case 'clinic_admin_id':
                    case 'clinic_logo':
                    case 'profile_image':
                        $update_data[ $field ] = (int) $value;
                        break;
                    case 'address':
                        $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 )
            );
        }

        $update_data = array_map( array( self::class, 'prepare_for_db' ), $update_data );

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

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

        return true;
    }

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

        // Check for dependencies
        if ( self::has_dependencies( $clinic_id ) ) {
            return new \WP_Error(
                'clinic_has_dependencies',
                'Cannot delete clinic with associated appointments or patients',
                array( 'status' => 409 )
            );
        }

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

        $result = $wpdb->delete(
            $table,
            array( 'id' => $clinic_id ),
            array( '%d' )
        );

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

        return true;
    }

    /**
     * Get clinic by ID
     *
     * @param int $clinic_id Clinic ID
     * @return array|null Clinic data or null if not found
     * @since 1.0.0
     */
    public static function get_by_id( $clinic_id ) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

        $clinic = $wpdb->get_row(
            $wpdb->prepare(
                "SELECT * FROM {$table} WHERE id = %d",
                $clinic_id
            ),
            ARRAY_A
        );

        if ( $clinic ) {
            return self::format_clinic_data( $clinic );
        }

        return null;
    }

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

        $defaults = array(
            'status' => null,
            'search' => '',
            'limit' => 50,
            'offset' => 0,
            'orderby' => 'name',
            'order' => 'ASC'
        );

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

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

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

        // Search filter
        if ( ! empty( $args['search'] ) ) {
            $where_clauses[] = '(name LIKE %s OR email LIKE %s OR city LIKE %s)';
            $search_term = '%' . $wpdb->esc_like( $args['search'] ) . '%';
            $where_values[] = $search_term;
            $where_values[] = $search_term;
            $where_values[] = $search_term;
        }

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

        // Whitelist for orderby
        $allowed_orderby = array( 'name', 'email', 'city', 'status', 'created_at' );
        $orderby = in_array( $args['orderby'], $allowed_orderby, true ) ? $args['orderby'] : 'name';
        
        // Whitelist for order
        $order = in_array( strtoupper( $args['order'] ), array( 'ASC', 'DESC' ), true ) ? strtoupper( $args['order'] ) : 'ASC';

        // Build query
        $query = "SELECT * FROM {$table} 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'] )
            )
        );

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

        return array_map( array( self::class, 'format_clinic_data' ), $clinics );
    }

    /**
     * Get total count of clinics
     *
     * @param array $args Filter arguments
     * @return int Total count
     * @since 1.0.0
     */
    public static function get_count( $args = array() ) {
        global $wpdb;
        $table = $wpdb->prefix . self::$table_name;

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

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

        if ( ! empty( $args['search'] ?? '' ) ) {
            $where_clauses[] = '(name LIKE %s OR email LIKE %s OR city LIKE %s)';
            $search_term = '%' . $wpdb->esc_like( $args['search'] ) . '%';
            $where_values[] = $search_term;
            $where_values[] = $search_term;
            $where_values[] = $search_term;
        }

        $where_sql = implode( ' AND ', $where_clauses );
        $query = "SELECT COUNT(*) FROM {$table} WHERE {$where_sql}";

        return (int) $wpdb->get_var( $wpdb->prepare( $query, $where_values ) );
    }

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

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

        return (int) $count > 0;
    }

    /**
     * Check if clinic has dependencies (appointments, patients, etc.)
     *
     * @param int $clinic_id Clinic ID
     * @return bool True if has dependencies, false otherwise
     * @since 1.0.0
     */
    private static function has_dependencies( $clinic_id ) {
        global $wpdb;

        // Check appointments
        $appointments_count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_appointments WHERE clinic_id = %d",
                $clinic_id
            )
        );

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

        // Check patient mappings
        $patients_count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_patient_clinic_mappings WHERE clinic_id = %d",
                $clinic_id
            )
        );

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

        // Check doctor mappings
        $doctors_count = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_doctor_clinic_mappings WHERE clinic_id = %d",
                $clinic_id
            )
        );

        return (int) $doctors_count > 0;
    }

    /**
     * Validate clinic data
     *
     * @param array $clinic_data Clinic data to validate
     * @return bool|WP_Error True if valid, WP_Error if invalid
     * @since 1.0.0
     */
    private static function validate_clinic_data( $clinic_data ) {
        $errors = array();

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

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

        // Check for duplicate email
        if ( ! empty( $clinic_data['email'] ) ) {
            global $wpdb;
            $table = $wpdb->prefix . self::$table_name;

            $existing_clinic = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT id FROM {$table} WHERE email = %s",
                    $clinic_data['email']
                )
            );

            if ( $existing_clinic ) {
                $errors[] = 'A clinic with this email already exists';
            }
        }

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

        return true;
    }

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

        // Parse JSON fields
        if ( ! empty( $clinic_data['specialties'] ) ) {
            $clinic_data['specialties'] = json_decode( $clinic_data['specialties'], true ) ?: array();
        }

        if ( ! empty( $clinic_data['extra'] ) ) {
            $clinic_data['extra'] = json_decode( $clinic_data['extra'], true ) ?: array();
        }

        // Cast numeric fields
        $numeric_fields = array( 'id', 'status', 'clinic_admin_id', 'clinic_logo', 'profile_image' );
        foreach ( $numeric_fields as $field ) {
            if ( isset( $clinic_data[ $field ] ) ) {
                $clinic_data[ $field ] = (int) $clinic_data[ $field ];
            }
        }

        return $clinic_data;
    }

    /**
     * Prepare data for database insertion/update
     *
     * @param mixed $value Data value
     * @return mixed Prepared value
     * @since 1.0.0
     */
    private static function prepare_for_db( $value ) {
        if ( is_null( $value ) ) {
            return null;
        }
        
        if ( is_array( $value ) ) {
            return wp_json_encode( $value );
        }
        
        return $value;
    }

    /**
     * Get clinic statistics
     *
     * @param int $clinic_id Clinic ID
     * @return array Clinic statistics
     * @since 1.0.0
     */
    public static function get_statistics( $clinic_id ) {
        global $wpdb;

        $stats = array(
            'total_appointments' => 0,
            'total_patients' => 0,
            'total_doctors' => 0,
            'revenue_this_month' => 0,
            'appointments_today' => 0
        );

        // Total appointments
        $stats['total_appointments'] = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_appointments WHERE clinic_id = %d",
                $clinic_id
            )
        );

        // Total patients
        $stats['total_patients'] = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_patient_clinic_mappings WHERE clinic_id = %d",
                $clinic_id
            )
        );

        // Total doctors
        $stats['total_doctors'] = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_doctor_clinic_mappings WHERE clinic_id = %d",
                $clinic_id
            )
        );

        // Revenue this month
        $stats['revenue_this_month'] = (float) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT SUM(CAST(actual_amount AS DECIMAL(10,2))) 
                 FROM {$wpdb->prefix}kc_bills 
                 WHERE clinic_id = %d 
                 AND MONTH(created_at) = MONTH(CURRENT_DATE()) 
                 AND YEAR(created_at) = YEAR(CURRENT_DATE())
                 AND payment_status = 'paid'",
                $clinic_id
            )
        ) ?: 0;

        // Appointments today
        $stats['appointments_today'] = (int) $wpdb->get_var(
            $wpdb->prepare(
                "SELECT COUNT(*) FROM {$wpdb->prefix}kc_appointments 
                 WHERE clinic_id = %d 
                 AND appointment_start_date = CURDATE()",
                $clinic_id
            )
        );

        return $stats;
    }
}