<?php
/**
 * Cross-Service Integration Service
 *
 * Handles integration between different API services and components
 *
 * @package Care_API
 * @subpackage Services
 * @version    1.0.0
 * @author     Descomplicar® <dev@descomplicar.pt>
 * @link       https://descomplicar.pt
 * @since      1.0.0
 */

namespace Care_API\Services;

use Care_API\Utils\API_Logger;
use Care_API\Utils\Error_Handler;
use WP_Error;

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

/**
 * Class Integration_Service
 *
 * Provides cross-service integration and coordination
 *
 * @since 1.0.0
 */
class Integration_Service {

    /**
     * Service registry
     *
     * @var array
     */
    private static $services = array();

    /**
     * Event hooks registry
     *
     * @var array
     */
    private static $hooks = array();

    /**
     * Integration cache
     *
     * @var array
     */
    private static $cache = array();

    /**
     * Initialize integration service
     *
     * @since 1.0.0
     */
    public static function init() {
        // Register core services
        self::register_core_services();
        
        // Setup service hooks
        self::setup_service_hooks();
        
        // Initialize event system
        self::init_event_system();
    }

    /**
     * Register core services
     *
     * @since 1.0.0
     */
    private static function register_core_services() {
        self::$services = array(
            'auth' => 'Care_API\\Services\\Auth_Service',
            'patient' => 'Care_API\\Services\\Database\\Patient_Service',
            'doctor' => 'Care_API\\Services\\Database\\Doctor_Service',
            'appointment' => 'Care_API\\Services\\Database\\Appointment_Service',
            'encounter' => 'Care_API\\Services\\Database\\Encounter_Service',
            'prescription' => 'Care_API\\Services\\Database\\Prescription_Service',
            'bill' => 'Care_API\\Services\\Database\\Bill_Service',
            'clinic' => 'Care_API\\Services\\Database\\Clinic_Service',
            'clinic_isolation' => 'Care_API\\Services\\Clinic_Isolation_Service'
        );
    }

    /**
     * Setup service integration hooks
     *
     * @since 1.0.0
     */
    private static function setup_service_hooks() {
        // Patient-related integrations
        add_action( 'kivicare_patient_created', array( __CLASS__, 'handle_patient_created' ), 10, 2 );
        add_action( 'kivicare_patient_updated', array( __CLASS__, 'handle_patient_updated' ), 10, 2 );
        
        // Appointment-related integrations
        add_action( 'kivicare_appointment_created', array( __CLASS__, 'handle_appointment_created' ), 10, 2 );
        add_action( 'kivicare_appointment_updated', array( __CLASS__, 'handle_appointment_updated' ), 10, 2 );
        add_action( 'kivicare_appointment_cancelled', array( __CLASS__, 'handle_appointment_cancelled' ), 10, 2 );
        
        // Encounter-related integrations
        add_action( 'kivicare_encounter_created', array( __CLASS__, 'handle_encounter_created' ), 10, 2 );
        add_action( 'kivicare_encounter_updated', array( __CLASS__, 'handle_encounter_updated' ), 10, 2 );
        add_action( 'kivicare_encounter_finalized', array( __CLASS__, 'handle_encounter_finalized' ), 10, 2 );
        
        // Prescription-related integrations
        add_action( 'kivicare_prescription_created', array( __CLASS__, 'handle_prescription_created' ), 10, 2 );
        add_action( 'kivicare_prescription_updated', array( __CLASS__, 'handle_prescription_updated' ), 10, 2 );
        
        // Bill-related integrations
        add_action( 'kivicare_bill_created', array( __CLASS__, 'handle_bill_created' ), 10, 2 );
        add_action( 'kivicare_bill_paid', array( __CLASS__, 'handle_bill_paid' ), 10, 2 );
    }

    /**
     * Initialize event system
     *
     * @since 1.0.0
     */
    private static function init_event_system() {
        self::$hooks = array(
            'before_create' => array(),
            'after_create' => array(),
            'before_update' => array(),
            'after_update' => array(),
            'before_delete' => array(),
            'after_delete' => array(),
            'on_status_change' => array(),
            'on_validation_error' => array(),
            'on_permission_denied' => array()
        );
    }

    /**
     * Register service
     *
     * @param string $service_name Service name
     * @param string $service_class Service class name
     * @return bool Success status
     * @since 1.0.0
     */
    public static function register_service( $service_name, $service_class ) {
        if ( ! class_exists( $service_class ) ) {
            API_Logger::log_critical_event( 
                'service_registration_failed',
                "Service class {$service_class} not found",
                array( 'service_name' => $service_name )
            );
            return false;
        }

        self::$services[$service_name] = $service_class;
        
        API_Logger::log_business_event( 
            'service_registered',
            "Service {$service_name} registered with class {$service_class}"
        );
        
        return true;
    }

    /**
     * Get service instance
     *
     * @param string $service_name Service name
     * @return object|null Service instance or null if not found
     * @since 1.0.0
     */
    public static function get_service( $service_name ) {
        if ( ! isset( self::$services[$service_name] ) ) {
            return null;
        }

        $service_class = self::$services[$service_name];
        
        // Check cache first
        $cache_key = "service_{$service_name}";
        if ( isset( self::$cache[$cache_key] ) ) {
            return self::$cache[$cache_key];
        }

        // Create instance
        if ( method_exists( $service_class, 'instance' ) ) {
            $instance = $service_class::instance();
        } elseif ( method_exists( $service_class, 'getInstance' ) ) {
            $instance = $service_class::getInstance();
        } else {
            $instance = new $service_class();
        }

        self::$cache[$cache_key] = $instance;
        return $instance;
    }

    /**
     * Execute cross-service operation
     *
     * @param string $operation Operation name
     * @param array  $params    Operation parameters
     * @return mixed Operation result
     * @since 1.0.0
     */
    public static function execute_operation( $operation, $params = array() ) {
        $start_time = microtime( true );
        
        API_Logger::log_business_event( 
            'cross_service_operation_started',
            "Executing operation: {$operation}",
            array( 'params' => $params )
        );

        $result = null;
        
        try {
            switch ( $operation ) {
                case 'create_patient_with_appointment':
                    $result = self::create_patient_with_appointment( $params );
                    break;
                    
                case 'complete_appointment_workflow':
                    $result = self::complete_appointment_workflow( $params );
                    break;
                    
                case 'generate_encounter_summary':
                    $result = self::generate_encounter_summary( $params );
                    break;
                    
                case 'process_bulk_prescriptions':
                    $result = self::process_bulk_prescriptions( $params );
                    break;
                    
                case 'calculate_clinic_statistics':
                    $result = self::calculate_clinic_statistics( $params );
                    break;
                    
                case 'sync_appointment_billing':
                    $result = self::sync_appointment_billing( $params );
                    break;
                    
                default:
                    throw new \Exception( "Unknown operation: {$operation}" );
            }
            
        } catch ( \Exception $e ) {
            $result = new WP_Error( 
                'operation_failed',
                $e->getMessage(),
                array( 'operation' => $operation, 'params' => $params )
            );
        }

        $execution_time = ( microtime( true ) - $start_time ) * 1000;
        
        API_Logger::log_business_event( 
            'cross_service_operation_completed',
            "Operation {$operation} completed in {$execution_time}ms",
            array( 'success' => ! is_wp_error( $result ) )
        );

        return $result;
    }

    /**
     * Create patient with appointment in single transaction
     *
     * @param array $params Patient and appointment data
     * @return array|WP_Error Result with patient and appointment IDs
     * @since 1.0.0
     */
    private static function create_patient_with_appointment( $params ) {
        global $wpdb;
        
        // Start transaction
        $wpdb->query( 'START TRANSACTION' );
        
        try {
            // Create patient
            $patient_service = self::get_service( 'patient' );
            $patient_result = $patient_service->create( $params['patient_data'] );
            
            if ( is_wp_error( $patient_result ) ) {
                throw new \Exception( $patient_result->get_error_message() );
            }
            
            // Create appointment
            $appointment_data = $params['appointment_data'];
            $appointment_data['patient_id'] = $patient_result['id'];
            
            $appointment_service = self::get_service( 'appointment' );
            $appointment_result = $appointment_service->create( $appointment_data );
            
            if ( is_wp_error( $appointment_result ) ) {
                throw new \Exception( $appointment_result->get_error_message() );
            }
            
            // Commit transaction
            $wpdb->query( 'COMMIT' );
            
            return array(
                'patient_id' => $patient_result['id'],
                'appointment_id' => $appointment_result['id'],
                'patient_data' => $patient_result,
                'appointment_data' => $appointment_result
            );
            
        } catch ( \Exception $e ) {
            $wpdb->query( 'ROLLBACK' );
            
            return new WP_Error( 
                'patient_appointment_creation_failed',
                $e->getMessage()
            );
        }
    }

    /**
     * Complete appointment workflow (appointment -> encounter -> billing)
     *
     * @param array $params Workflow parameters
     * @return array|WP_Error Workflow result
     * @since 1.0.0
     */
    private static function complete_appointment_workflow( $params ) {
        global $wpdb;
        
        $appointment_id = $params['appointment_id'];
        $encounter_data = $params['encounter_data'] ?? array();
        $billing_data = $params['billing_data'] ?? array();
        
        // Start transaction
        $wpdb->query( 'START TRANSACTION' );
        
        try {
            // Get appointment details
            $appointment_service = self::get_service( 'appointment' );
            $appointment = $appointment_service->get_by_id( $appointment_id );
            
            if ( ! $appointment ) {
                throw new \Exception( 'Appointment not found' );
            }
            
            // Create encounter
            $encounter_data = array_merge( array(
                'patient_id' => $appointment->patient_id,
                'doctor_id' => $appointment->doctor_id,
                'clinic_id' => $appointment->clinic_id,
                'appointment_id' => $appointment_id,
                'encounter_date' => current_time( 'Y-m-d H:i:s' ),
                'status' => 'completed'
            ), $encounter_data );
            
            $encounter_service = self::get_service( 'encounter' );
            $encounter_result = $encounter_service->create( $encounter_data );
            
            if ( is_wp_error( $encounter_result ) ) {
                throw new \Exception( $encounter_result->get_error_message() );
            }
            
            // Create billing if provided
            $bill_result = null;
            if ( ! empty( $billing_data ) ) {
                $billing_data = array_merge( array(
                    'encounter_id' => $encounter_result['id'],
                    'appointment_id' => $appointment_id,
                    'clinic_id' => $appointment->clinic_id,
                    'patient_id' => $appointment->patient_id,
                    'bill_date' => current_time( 'Y-m-d' ),
                    'status' => 'pending'
                ), $billing_data );
                
                $bill_service = self::get_service( 'bill' );
                $bill_result = $bill_service->create( $billing_data );
                
                if ( is_wp_error( $bill_result ) ) {
                    throw new \Exception( $bill_result->get_error_message() );
                }
            }
            
            // Update appointment status to completed
            $appointment_service->update( $appointment_id, array( 'status' => 2 ) ); // 2 = completed
            
            // Commit transaction
            $wpdb->query( 'COMMIT' );
            
            // Trigger completion hooks
            do_action( 'kivicare_appointment_workflow_completed', $appointment_id, array(
                'encounter_id' => $encounter_result['id'],
                'bill_id' => $bill_result ? $bill_result['id'] : null
            ) );
            
            return array(
                'appointment_id' => $appointment_id,
                'encounter_id' => $encounter_result['id'],
                'bill_id' => $bill_result ? $bill_result['id'] : null,
                'status' => 'completed'
            );
            
        } catch ( \Exception $e ) {
            $wpdb->query( 'ROLLBACK' );
            
            return new WP_Error( 
                'appointment_workflow_failed',
                $e->getMessage()
            );
        }
    }

    /**
     * Generate comprehensive encounter summary
     *
     * @param array $params Summary parameters
     * @return array|WP_Error Encounter summary
     * @since 1.0.0
     */
    private static function generate_encounter_summary( $params ) {
        $encounter_id = $params['encounter_id'];
        
        $encounter_service = self::get_service( 'encounter' );
        $prescription_service = self::get_service( 'prescription' );
        
        // Get encounter details
        $encounter = $encounter_service->get_by_id( $encounter_id );
        if ( ! $encounter ) {
            return new WP_Error( 'encounter_not_found', 'Encounter not found' );
        }
        
        // Get related prescriptions
        $prescriptions = $prescription_service->get_by_encounter( $encounter_id );
        
        // Get patient information
        $patient_service = self::get_service( 'patient' );
        $patient = $patient_service->get_by_id( $encounter->patient_id );
        
        // Get doctor information
        $doctor_service = self::get_service( 'doctor' );
        $doctor = $doctor_service->get_by_id( $encounter->doctor_id );
        
        // Build comprehensive summary
        $summary = array(
            'encounter' => $encounter,
            'patient' => array(
                'id' => $patient->ID,
                'name' => $patient->first_name . ' ' . $patient->last_name,
                'email' => $patient->user_email,
                'age' => self::calculate_age( $patient->dob ),
                'contact' => $patient->contact_no
            ),
            'doctor' => array(
                'id' => $doctor->ID,
                'name' => $doctor->first_name . ' ' . $doctor->last_name,
                'specialization' => $doctor->specialties ?? 'General Medicine'
            ),
            'prescriptions' => array_map( function( $prescription ) {
                return array(
                    'medication' => $prescription->name,
                    'dosage' => $prescription->frequency,
                    'duration' => $prescription->duration,
                    'instructions' => $prescription->instruction
                );
            }, $prescriptions ),
            'summary_stats' => array(
                'total_prescriptions' => count( $prescriptions ),
                'encounter_duration' => self::calculate_encounter_duration( $encounter ),
                'follow_up_required' => ! empty( $encounter->follow_up_date )
            )
        );
        
        return $summary;
    }

    /**
     * Process bulk prescriptions
     *
     * @param array $params Bulk prescription parameters
     * @return array|WP_Error Processing result
     * @since 1.0.0
     */
    private static function process_bulk_prescriptions( $params ) {
        $prescriptions = $params['prescriptions'];
        $encounter_id = $params['encounter_id'];
        
        global $wpdb;
        $wpdb->query( 'START TRANSACTION' );
        
        $results = array(
            'success' => array(),
            'failed' => array()
        );
        
        try {
            $prescription_service = self::get_service( 'prescription' );
            
            foreach ( $prescriptions as $prescription_data ) {
                $prescription_data['encounter_id'] = $encounter_id;
                
                $result = $prescription_service->create( $prescription_data );
                
                if ( is_wp_error( $result ) ) {
                    $results['failed'][] = array(
                        'prescription' => $prescription_data,
                        'error' => $result->get_error_message()
                    );
                } else {
                    $results['success'][] = $result;
                }
            }
            
            // If any failed, rollback all
            if ( ! empty( $results['failed'] ) && ! $params['partial_success'] ) {
                $wpdb->query( 'ROLLBACK' );
                return new WP_Error( 'bulk_prescription_failed', 'Some prescriptions failed', $results );
            }
            
            $wpdb->query( 'COMMIT' );
            return $results;
            
        } catch ( \Exception $e ) {
            $wpdb->query( 'ROLLBACK' );
            return new WP_Error( 'bulk_prescription_error', $e->getMessage() );
        }
    }

    /**
     * Calculate clinic statistics
     *
     * @param array $params Statistics parameters
     * @return array Clinic statistics
     * @since 1.0.0
     */
    private static function calculate_clinic_statistics( $params ) {
        $clinic_id = $params['clinic_id'];
        $date_range = $params['date_range'] ?? array(
            'start' => date( 'Y-m-d', strtotime( '-30 days' ) ),
            'end' => date( 'Y-m-d' )
        );
        
        global $wpdb;
        
        $stats = array(
            'clinic_id' => $clinic_id,
            'date_range' => $date_range,
            'appointments' => array(),
            'encounters' => array(),
            'prescriptions' => array(),
            'billing' => array(),
            'patients' => array()
        );
        
        // Appointment statistics
        $appointment_stats = $wpdb->get_row( $wpdb->prepare(
            "SELECT 
                COUNT(*) as total,
                COUNT(CASE WHEN status = 1 THEN 1 END) as scheduled,
                COUNT(CASE WHEN status = 2 THEN 1 END) as completed,
                COUNT(CASE WHEN status = 3 THEN 1 END) as cancelled
            FROM {$wpdb->prefix}kc_appointments 
            WHERE clinic_id = %d 
            AND appointment_start_date BETWEEN %s AND %s",
            $clinic_id, $date_range['start'], $date_range['end']
        ) );
        $stats['appointments'] = $appointment_stats;
        
        // Encounter statistics
        $encounter_stats = $wpdb->get_row( $wpdb->prepare(
            "SELECT 
                COUNT(*) as total,
                COUNT(CASE WHEN status = 'completed' THEN 1 END) as completed,
                AVG(TIMESTAMPDIFF(MINUTE, created_at, updated_at)) as avg_duration
            FROM {$wpdb->prefix}kc_patient_encounters 
            WHERE clinic_id = %d 
            AND encounter_date BETWEEN %s AND %s",
            $clinic_id, $date_range['start'], $date_range['end']
        ) );
        $stats['encounters'] = $encounter_stats;
        
        // Prescription statistics
        $prescription_stats = $wpdb->get_row( $wpdb->prepare(
            "SELECT 
                COUNT(*) as total,
                COUNT(DISTINCT patient_id) as unique_patients
            FROM {$wpdb->prefix}kc_prescription p
            INNER JOIN {$wpdb->prefix}kc_patient_encounters e ON p.encounter_id = e.id
            WHERE e.clinic_id = %d 
            AND e.encounter_date BETWEEN %s AND %s",
            $clinic_id, $date_range['start'], $date_range['end']
        ) );
        $stats['prescriptions'] = $prescription_stats;
        
        // Billing statistics
        $billing_stats = $wpdb->get_row( $wpdb->prepare(
            "SELECT 
                COUNT(*) as total_bills,
                SUM(CASE WHEN payment_status = 'paid' THEN CAST(total_amount AS DECIMAL(10,2)) ELSE 0 END) as total_revenue,
                SUM(CAST(total_amount AS DECIMAL(10,2))) as total_billed,
                COUNT(CASE WHEN payment_status = 'paid' THEN 1 END) as paid_bills
            FROM {$wpdb->prefix}kc_bills 
            WHERE clinic_id = %d 
            AND created_at BETWEEN %s AND %s",
            $clinic_id, $date_range['start'] . ' 00:00:00', $date_range['end'] . ' 23:59:59'
        ) );
        $stats['billing'] = $billing_stats;
        
        // Patient statistics
        $patient_stats = $wpdb->get_row( $wpdb->prepare(
            "SELECT 
                COUNT(DISTINCT patient_id) as total_patients,
                COUNT(DISTINCT CASE WHEN appointment_start_date BETWEEN %s AND %s THEN patient_id END) as active_patients
            FROM {$wpdb->prefix}kc_appointments 
            WHERE clinic_id = %d",
            $date_range['start'], $date_range['end'], $clinic_id
        ) );
        $stats['patients'] = $patient_stats;
        
        return $stats;
    }

    /**
     * Sync appointment billing data
     *
     * @param array $params Sync parameters
     * @return array|WP_Error Sync result
     * @since 1.0.0
     */
    private static function sync_appointment_billing( $params ) {
        $appointment_id = $params['appointment_id'];
        $billing_data = $params['billing_data'];
        
        $appointment_service = self::get_service( 'appointment' );
        $bill_service = self::get_service( 'bill' );
        
        // Get appointment
        $appointment = $appointment_service->get_by_id( $appointment_id );
        if ( ! $appointment ) {
            return new WP_Error( 'appointment_not_found', 'Appointment not found' );
        }
        
        // Check if bill already exists
        $existing_bill = $bill_service->get_by_appointment( $appointment_id );
        
        $billing_data = array_merge( array(
            'appointment_id' => $appointment_id,
            'clinic_id' => $appointment->clinic_id,
            'title' => 'Appointment Consultation',
            'bill_date' => $appointment->appointment_start_date,
            'status' => 'pending'
        ), $billing_data );
        
        if ( $existing_bill ) {
            // Update existing bill
            $result = $bill_service->update( $existing_bill->id, $billing_data );
            $action = 'updated';
        } else {
            // Create new bill
            $result = $bill_service->create( $billing_data );
            $action = 'created';
        }
        
        if ( is_wp_error( $result ) ) {
            return $result;
        }
        
        return array(
            'action' => $action,
            'bill_id' => $result['id'],
            'appointment_id' => $appointment_id
        );
    }

    /**
     * Event handlers for cross-service integration
     */

    /**
     * Handle patient created event
     *
     * @param int   $patient_id Patient ID
     * @param array $patient_data Patient data
     * @since 1.0.0
     */
    public static function handle_patient_created( $patient_id, $patient_data ) {
        API_Logger::log_business_event( 
            'patient_created',
            "Patient {$patient_id} created",
            array( 'clinic_id' => $patient_data['clinic_id'] ?? null )
        );
        
        // Additional integrations can be added here
        do_action( 'kivicare_patient_post_created', $patient_id, $patient_data );
    }

    /**
     * Handle appointment created event
     *
     * @param int   $appointment_id Appointment ID
     * @param array $appointment_data Appointment data
     * @since 1.0.0
     */
    public static function handle_appointment_created( $appointment_id, $appointment_data ) {
        API_Logger::log_business_event( 
            'appointment_created',
            "Appointment {$appointment_id} created",
            array( 'patient_id' => $appointment_data['patient_id'], 'doctor_id' => $appointment_data['doctor_id'] )
        );
        
        // Send notifications, calendar invites, etc.
        do_action( 'kivicare_appointment_post_created', $appointment_id, $appointment_data );
    }

    /**
     * Handle encounter finalized event
     *
     * @param int   $encounter_id Encounter ID
     * @param array $encounter_data Encounter data
     * @since 1.0.0
     */
    public static function handle_encounter_finalized( $encounter_id, $encounter_data ) {
        API_Logger::log_business_event( 
            'encounter_finalized',
            "Encounter {$encounter_id} finalized"
        );
        
        // Trigger billing, reports, etc.
        do_action( 'kivicare_encounter_post_finalized', $encounter_id, $encounter_data );
    }

    /**
     * Utility methods
     */

    /**
     * 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 ( ! $dob ) return 0;
        
        $birth_date = new \DateTime( $dob );
        $current_date = new \DateTime();
        return $current_date->diff( $birth_date )->y;
    }

    /**
     * Calculate encounter duration
     *
     * @param object $encounter Encounter object
     * @return int Duration in minutes
     * @since 1.0.0
     */
    private static function calculate_encounter_duration( $encounter ) {
        if ( ! $encounter->created_at || ! $encounter->updated_at ) {
            return 0;
        }
        
        $start = new \DateTime( $encounter->created_at );
        $end = new \DateTime( $encounter->updated_at );
        return $end->diff( $start )->i;
    }
}