<?php
/**
 * Bill Database Service
 *
 * Handles advanced bill 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\Bill;
use Care_API\Services\Permission_Service;

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

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

    /**
     * Bill status constants
     */
    const STATUS_DRAFT = 'draft';
    const STATUS_PENDING = 'pending';
    const STATUS_PAID = 'paid';
    const STATUS_OVERDUE = 'overdue';
    const STATUS_CANCELLED = 'cancelled';
    const STATUS_REFUNDED = 'refunded';

    /**
     * Initialize the service
     *
     * @since 1.0.0
     */
    public static function init() {
        // Hook into WordPress actions
        add_action( 'kivicare_bill_created', array( self::class, 'on_bill_created' ), 10, 2 );
        add_action( 'kivicare_bill_updated', array( self::class, 'on_bill_updated' ), 10, 2 );
        add_action( 'kivicare_bill_paid', array( self::class, 'on_bill_paid' ), 10, 1 );
        add_action( 'kivicare_bill_overdue', array( self::class, 'on_bill_overdue' ), 10, 1 );

        // Schedule overdue bill checks
        add_action( 'kivicare_check_overdue_bills', array( self::class, 'check_overdue_bills' ) );
        if ( ! wp_next_scheduled( 'kivicare_check_overdue_bills' ) ) {
            wp_schedule_event( time(), 'daily', 'kivicare_check_overdue_bills' );
        }
    }

    /**
     * Create bill with advanced business logic
     *
     * @param array $bill_data Bill data
     * @param int   $user_id   Creating user ID
     * @return array|WP_Error Bill data or error
     * @since 1.0.0
     */
    public static function create_bill( $bill_data, $user_id = null ) {
        // Permission check
        if ( ! Permission_Service::can_manage_billing( get_current_user_id(), $bill_data['clinic_id'] ?? 0 ) ) {
            return new \WP_Error(
                'insufficient_permissions',
                'You do not have permission to create bills',
                array( 'status' => 403 )
            );
        }

        // Enhanced validation
        $validation = self::validate_bill_business_rules( $bill_data );
        if ( is_wp_error( $validation ) ) {
            return $validation;
        }

        // Add metadata
        $bill_data['created_by'] = $user_id ?: get_current_user_id();
        $bill_data['created_at'] = current_time( 'mysql' );
        $bill_data['status'] = self::STATUS_DRAFT;

        // Generate bill number if not provided
        if ( empty( $bill_data['bill_number'] ) ) {
            $bill_data['bill_number'] = self::generate_bill_number( $bill_data['clinic_id'] );
        }

        // Set bill date if not provided
        if ( empty( $bill_data['bill_date'] ) ) {
            $bill_data['bill_date'] = current_time( 'Y-m-d' );
        }

        // Calculate totals
        $bill_data = self::calculate_bill_totals( $bill_data );

        // Set due date if not provided
        if ( empty( $bill_data['due_date'] ) ) {
            $due_days = get_option( 'kivicare_default_bill_due_days', 30 );
            $bill_data['due_date'] = date( 'Y-m-d', strtotime( "+{$due_days} days" ) );
        }

        // Create bill
        $bill_id = Bill::create( $bill_data );
        
        if ( is_wp_error( $bill_id ) ) {
            return $bill_id;
        }

        // Post-creation tasks
        self::setup_bill_defaults( $bill_id, $bill_data );
        
        // Auto-finalize if specified
        if ( ! empty( $bill_data['auto_finalize'] ) ) {
            self::finalize_bill( $bill_id );
        }
        
        // Trigger action
        do_action( 'kivicare_bill_created', $bill_id, $bill_data );

        // Return full bill data
        return self::get_bill_with_metadata( $bill_id );
    }

    /**
     * Update bill with business logic
     *
     * @param int   $bill_id   Bill ID
     * @param array $bill_data Updated data
     * @return array|WP_Error Updated bill data or error
     * @since 1.0.0
     */
    public static function update_bill( $bill_id, $bill_data ) {
        // Get current bill data
        $current_bill = Bill::get_by_id( $bill_id );
        if ( ! $current_bill ) {
            return new \WP_Error(
                'bill_not_found',
                'Bill not found',
                array( 'status' => 404 )
            );
        }

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

        // Check if bill can be modified
        if ( in_array( $current_bill['status'], array( self::STATUS_PAID, self::STATUS_REFUNDED ) ) ) {
            return new \WP_Error(
                'cannot_modify_bill',
                'Cannot modify a paid or refunded bill',
                array( 'status' => 400 )
            );
        }

        // Enhanced validation
        $validation = self::validate_bill_business_rules( $bill_data, $bill_id );
        if ( is_wp_error( $validation ) ) {
            return $validation;
        }

        // Recalculate totals if items changed
        if ( isset( $bill_data['items'] ) ) {
            $bill_data = self::calculate_bill_totals( $bill_data );
        }

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

        // Update bill
        $result = Bill::update( $bill_id, $bill_data );
        
        if ( is_wp_error( $result ) ) {
            return $result;
        }

        // Handle status changes
        self::handle_status_changes( $bill_id, $current_bill, $bill_data );

        // Handle payment updates
        if ( isset( $bill_data['payment_status'] ) || isset( $bill_data['amount_paid'] ) ) {
            self::handle_payment_updates( $bill_id, $current_bill, $bill_data );
        }

        // Trigger action
        do_action( 'kivicare_bill_updated', $bill_id, $bill_data );

        // Return updated bill data
        return self::get_bill_with_metadata( $bill_id );
    }

    /**
     * Process payment for bill
     *
     * @param int   $bill_id      Bill ID
     * @param array $payment_data Payment data
     * @return array|WP_Error Updated bill data or error
     * @since 1.0.0
     */
    public static function process_payment( $bill_id, $payment_data ) {
        $bill = Bill::get_by_id( $bill_id );
        if ( ! $bill ) {
            return new \WP_Error(
                'bill_not_found',
                'Bill not found',
                array( 'status' => 404 )
            );
        }

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

        // Validate payment data
        $validation = self::validate_payment_data( $payment_data, $bill );
        if ( is_wp_error( $validation ) ) {
            return $validation;
        }

        // Calculate new paid amount
        $current_paid = (float) ( $bill['amount_paid'] ?? 0 );
        $payment_amount = (float) $payment_data['amount'];
        $new_paid_amount = $current_paid + $payment_amount;
        $total_amount = (float) $bill['total_amount'];

        // Determine new status
        $new_status = self::STATUS_PENDING;
        if ( $new_paid_amount >= $total_amount ) {
            $new_status = self::STATUS_PAID;
        }

        // Update bill with payment
        $update_data = array(
            'amount_paid' => $new_paid_amount,
            'status' => $new_status,
            'updated_by' => get_current_user_id(),
            'updated_at' => current_time( 'mysql' )
        );

        if ( $new_status === self::STATUS_PAID ) {
            $update_data['paid_date'] = current_time( 'mysql' );
        }

        $result = Bill::update( $bill_id, $update_data );
        
        if ( is_wp_error( $result ) ) {
            return $result;
        }

        // Record payment transaction
        self::record_payment_transaction( $bill_id, $payment_data );

        // Send payment confirmation
        if ( $new_status === self::STATUS_PAID ) {
            self::send_payment_confirmation( $bill_id );
            do_action( 'kivicare_bill_paid', $bill_id );
        }

        // Update patient account balance
        self::update_patient_account_balance( $bill['patient_id'] );

        return self::get_bill_with_metadata( $bill_id );
    }

    /**
     * Finalize bill (make it ready for payment)
     *
     * @param int   $bill_id      Bill ID
     * @param array $final_data   Final data
     * @return array|WP_Error Updated bill data or error
     * @since 1.0.0
     */
    public static function finalize_bill( $bill_id, $final_data = array() ) {
        $bill = Bill::get_by_id( $bill_id );
        if ( ! $bill ) {
            return new \WP_Error(
                'bill_not_found',
                'Bill not found',
                array( 'status' => 404 )
            );
        }

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

        // Check if already finalized or paid
        if ( in_array( $bill['status'], array( self::STATUS_PENDING, self::STATUS_PAID, self::STATUS_OVERDUE ) ) ) {
            return new \WP_Error(
                'already_finalized',
                'Bill is already finalized or paid',
                array( 'status' => 400 )
            );
        }

        // Validate finalization requirements
        $validation = self::validate_finalization_requirements( $bill_id );
        if ( is_wp_error( $validation ) ) {
            return $validation;
        }

        // Update bill status
        $update_data = array_merge( $final_data, array(
            'status' => self::STATUS_PENDING,
            'finalized_by' => get_current_user_id(),
            'finalized_at' => current_time( 'mysql' ),
            'updated_at' => current_time( 'mysql' )
        ));

        $result = Bill::update( $bill_id, $update_data );
        
        if ( is_wp_error( $result ) ) {
            return $result;
        }

        // Generate PDF invoice
        self::generate_invoice_pdf( $bill_id );

        // Send bill to patient
        self::send_bill_to_patient( $bill_id );

        // Update patient account balance
        self::update_patient_account_balance( $bill['patient_id'] );

        return self::get_bill_with_metadata( $bill_id );
    }

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

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

        // Add enhanced metadata
        $bill['patient'] = self::get_bill_patient( $bill['patient_id'] );
        $bill['clinic'] = self::get_bill_clinic( $bill['clinic_id'] );
        $bill['appointment'] = self::get_bill_appointment( $bill['appointment_id'] ?? null );
        $bill['encounter'] = self::get_bill_encounter( $bill['encounter_id'] ?? null );
        $bill['items'] = self::get_bill_items( $bill_id );
        $bill['payments'] = self::get_bill_payments( $bill_id );
        $bill['balance_due'] = (float) $bill['total_amount'] - (float) ( $bill['amount_paid'] ?? 0 );
        $bill['is_overdue'] = self::is_bill_overdue( $bill );
        $bill['days_overdue'] = self::get_days_overdue( $bill );

        return $bill;
    }

    /**
     * Search bills with advanced criteria
     *
     * @param array $filters Search filters
     * @return array Search results
     * @since 1.0.0
     */
    public static function search_bills( $filters = array() ) {
        global $wpdb;

        $user_id = get_current_user_id();
        $accessible_clinic_ids = Permission_Service::get_accessible_clinic_ids( $user_id );

        if ( empty( $accessible_clinic_ids ) ) {
            return array();
        }

        // Build search query
        $where_clauses = array( "b.clinic_id IN (" . implode( ',', $accessible_clinic_ids ) . ")" );
        $where_values = array();

        // Date range filter
        if ( ! empty( $filters['start_date'] ) ) {
            $where_clauses[] = "DATE(b.bill_date) >= %s";
            $where_values[] = $filters['start_date'];
        }

        if ( ! empty( $filters['end_date'] ) ) {
            $where_clauses[] = "DATE(b.bill_date) <= %s";
            $where_values[] = $filters['end_date'];
        }

        // Patient filter
        if ( ! empty( $filters['patient_id'] ) ) {
            $where_clauses[] = "b.patient_id = %d";
            $where_values[] = $filters['patient_id'];
        }

        // Clinic filter
        if ( ! empty( $filters['clinic_id'] ) && in_array( $filters['clinic_id'], $accessible_clinic_ids ) ) {
            $where_clauses[] = "b.clinic_id = %d";
            $where_values[] = $filters['clinic_id'];
        }

        // Status filter
        if ( ! empty( $filters['status'] ) ) {
            if ( is_array( $filters['status'] ) ) {
                $status_placeholders = implode( ',', array_fill( 0, count( $filters['status'] ), '%s' ) );
                $where_clauses[] = "b.status IN ({$status_placeholders})";
                $where_values = array_merge( $where_values, $filters['status'] );
            } else {
                $where_clauses[] = "b.status = %s";
                $where_values[] = $filters['status'];
            }
        }

        // Amount filter
        if ( isset( $filters['amount_min'] ) ) {
            $where_clauses[] = "b.total_amount >= %f";
            $where_values[] = $filters['amount_min'];
        }

        if ( isset( $filters['amount_max'] ) ) {
            $where_clauses[] = "b.total_amount <= %f";
            $where_values[] = $filters['amount_max'];
        }

        // Overdue filter
        if ( ! empty( $filters['overdue'] ) ) {
            $where_clauses[] = "b.due_date < CURDATE() AND b.status NOT IN ('paid', 'cancelled', 'refunded')";
        }

        // Search term
        if ( ! empty( $filters['search'] ) ) {
            $where_clauses[] = "(p.first_name LIKE %s OR p.last_name LIKE %s OR b.bill_number LIKE %s OR b.description LIKE %s)";
            $search_term = '%' . $wpdb->esc_like( $filters['search'] ) . '%';
            $where_values = array_merge( $where_values, array_fill( 0, 4, $search_term ) );
        }

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

        // Pagination
        $limit = isset( $filters['limit'] ) ? (int) $filters['limit'] : 20;
        $offset = isset( $filters['offset'] ) ? (int) $filters['offset'] : 0;

        $query = "SELECT b.*, 
                         p.first_name as patient_first_name, p.last_name as patient_last_name,
                         c.name as clinic_name,
                         (b.total_amount - COALESCE(b.amount_paid, 0)) as balance_due,
                         CASE WHEN b.due_date < CURDATE() AND b.status NOT IN ('paid', 'cancelled', 'refunded') THEN 1 ELSE 0 END as is_overdue
                  FROM {$wpdb->prefix}kc_bills b
                  LEFT JOIN {$wpdb->prefix}kc_patients p ON b.patient_id = p.id
                  LEFT JOIN {$wpdb->prefix}kc_clinics c ON b.clinic_id = c.id
                  WHERE {$where_sql}
                  ORDER BY b.bill_date DESC
                  LIMIT {$limit} OFFSET {$offset}";

        if ( ! empty( $where_values ) ) {
            $results = $wpdb->get_results( $wpdb->prepare( $query, $where_values ), ARRAY_A );
        } else {
            $results = $wpdb->get_results( $query, ARRAY_A );
        }

        // Get total count for pagination
        $count_query = "SELECT COUNT(*) FROM {$wpdb->prefix}kc_bills b
                        LEFT JOIN {$wpdb->prefix}kc_patients p ON b.patient_id = p.id
                        WHERE {$where_sql}";

        if ( ! empty( $where_values ) ) {
            $total = (int) $wpdb->get_var( $wpdb->prepare( $count_query, $where_values ) );
        } else {
            $total = (int) $wpdb->get_var( $count_query );
        }

        return array(
            'bills' => array_map( function( $bill ) {
                $bill['id'] = (int) $bill['id'];
                $bill['total_amount'] = (float) $bill['total_amount'];
                $bill['balance_due'] = (float) $bill['balance_due'];
                $bill['is_overdue'] = (bool) $bill['is_overdue'];
                return $bill;
            }, $results ),
            'total' => $total,
            'has_more' => ( $offset + $limit ) < $total
        );
    }

    /**
     * Get billing statistics
     *
     * @param array $filters Filters for statistics
     * @return array Statistics
     * @since 1.0.0
     */
    public static function get_billing_statistics( $filters = array() ) {
        global $wpdb;

        $user_id = get_current_user_id();
        $accessible_clinic_ids = Permission_Service::get_accessible_clinic_ids( $user_id );

        if ( empty( $accessible_clinic_ids ) ) {
            return array();
        }

        $where_clauses = array( "clinic_id IN (" . implode( ',', $accessible_clinic_ids ) . ")" );
        $where_values = array();

        // Date filter
        if ( ! empty( $filters['start_date'] ) && ! empty( $filters['end_date'] ) ) {
            $where_clauses[] = "bill_date BETWEEN %s AND %s";
            $where_values[] = $filters['start_date'];
            $where_values[] = $filters['end_date'];
        }

        // Clinic filter
        if ( ! empty( $filters['clinic_id'] ) && in_array( $filters['clinic_id'], $accessible_clinic_ids ) ) {
            $where_clauses[] = "clinic_id = %d";
            $where_values[] = $filters['clinic_id'];
        }

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

        $query = "SELECT 
                    COUNT(*) as total_bills,
                    SUM(total_amount) as total_billed,
                    SUM(COALESCE(amount_paid, 0)) as total_paid,
                    SUM(total_amount - COALESCE(amount_paid, 0)) as total_outstanding,
                    COUNT(CASE WHEN status = 'paid' THEN 1 END) as paid_bills,
                    COUNT(CASE WHEN status = 'pending' THEN 1 END) as pending_bills,
                    COUNT(CASE WHEN status = 'overdue' THEN 1 END) as overdue_bills,
                    COUNT(CASE WHEN due_date < CURDATE() AND status NOT IN ('paid', 'cancelled', 'refunded') THEN 1 END) as bills_overdue
                  FROM {$wpdb->prefix}kc_bills 
                  WHERE {$where_sql}";

        if ( ! empty( $where_values ) ) {
            $stats = $wpdb->get_row( $wpdb->prepare( $query, $where_values ), ARRAY_A );
        } else {
            $stats = $wpdb->get_row( $query, ARRAY_A );
        }

        // Calculate additional metrics
        $stats['collection_rate'] = $stats['total_billed'] > 0 ? 
            round( ( $stats['total_paid'] / $stats['total_billed'] ) * 100, 2 ) : 0;
        
        $stats['average_bill_amount'] = $stats['total_bills'] > 0 ? 
            round( $stats['total_billed'] / $stats['total_bills'], 2 ) : 0;

        return $stats;
    }

    /**
     * Generate unique bill number
     *
     * @param int $clinic_id Clinic ID
     * @return string Bill number
     * @since 1.0.0
     */
    private static function generate_bill_number( $clinic_id ) {
        global $wpdb;

        $prefix = 'B' . str_pad( $clinic_id, 3, '0', STR_PAD_LEFT ) . date( 'ym' );
        
        // Get the highest existing bill number for this clinic and month
        $max_number = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT MAX(CAST(SUBSTRING(bill_number, 8) AS UNSIGNED)) 
                 FROM {$wpdb->prefix}kc_bills 
                 WHERE bill_number LIKE %s",
                $prefix . '%'
            )
        );

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

    /**
     * Calculate bill totals
     *
     * @param array $bill_data Bill data
     * @return array Updated bill data with totals
     * @since 1.0.0
     */
    private static function calculate_bill_totals( $bill_data ) {
        $subtotal = 0;
        $tax_amount = 0;
        $discount_amount = 0;

        // Calculate subtotal from items
        if ( ! empty( $bill_data['items'] ) ) {
            foreach ( $bill_data['items'] as $item ) {
                $item_total = (float) $item['quantity'] * (float) $item['unit_price'];
                $subtotal += $item_total;
            }
        }

        // Apply discount
        if ( ! empty( $bill_data['discount_percentage'] ) ) {
            $discount_amount = $subtotal * ( (float) $bill_data['discount_percentage'] / 100 );
        } elseif ( ! empty( $bill_data['discount_amount'] ) ) {
            $discount_amount = (float) $bill_data['discount_amount'];
        }

        $subtotal_after_discount = $subtotal - $discount_amount;

        // Apply tax
        if ( ! empty( $bill_data['tax_percentage'] ) ) {
            $tax_amount = $subtotal_after_discount * ( (float) $bill_data['tax_percentage'] / 100 );
        } elseif ( ! empty( $bill_data['tax_amount'] ) ) {
            $tax_amount = (float) $bill_data['tax_amount'];
        }

        // Calculate total
        $total_amount = $subtotal_after_discount + $tax_amount;

        // Update bill data
        $bill_data['subtotal_amount'] = $subtotal;
        $bill_data['discount_amount'] = $discount_amount;
        $bill_data['tax_amount'] = $tax_amount;
        $bill_data['total_amount'] = $total_amount;

        return $bill_data;
    }

    /**
     * Additional helper methods for bill management
     */

    private static function validate_bill_business_rules( $bill_data, $bill_id = null ) {
        $errors = array();

        // Validate required fields
        $required_fields = array( 'patient_id', 'clinic_id' );
        
        foreach ( $required_fields as $field ) {
            if ( empty( $bill_data[$field] ) ) {
                $errors[] = "Field {$field} is required";
            }
        }

        // Validate patient exists
        if ( ! empty( $bill_data['patient_id'] ) ) {
            global $wpdb;
            $patient_exists = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT id FROM {$wpdb->prefix}kc_patients WHERE id = %d",
                    $bill_data['patient_id']
                )
            );
            
            if ( ! $patient_exists ) {
                $errors[] = 'Invalid patient ID';
            }
        }

        // Validate clinic exists
        if ( ! empty( $bill_data['clinic_id'] ) ) {
            global $wpdb;
            $clinic_exists = $wpdb->get_var(
                $wpdb->prepare(
                    "SELECT id FROM {$wpdb->prefix}kc_clinics WHERE id = %d",
                    $bill_data['clinic_id']
                )
            );
            
            if ( ! $clinic_exists ) {
                $errors[] = 'Invalid clinic ID';
            }
        }

        // Validate amounts are positive
        $amount_fields = array( 'subtotal_amount', 'tax_amount', 'discount_amount', 'total_amount' );
        foreach ( $amount_fields as $field ) {
            if ( isset( $bill_data[$field] ) && (float) $bill_data[$field] < 0 ) {
                $errors[] = "Field {$field} cannot be negative";
            }
        }

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

        return true;
    }

    private static function validate_payment_data( $payment_data, $bill ) {
        $errors = array();

        // Validate required fields
        if ( empty( $payment_data['amount'] ) ) {
            $errors[] = 'Payment amount is required';
        }

        if ( empty( $payment_data['method'] ) ) {
            $errors[] = 'Payment method is required';
        }

        // Validate payment amount
        $payment_amount = (float) $payment_data['amount'];
        if ( $payment_amount <= 0 ) {
            $errors[] = 'Payment amount must be positive';
        }

        $current_paid = (float) ( $bill['amount_paid'] ?? 0 );
        $total_amount = (float) $bill['total_amount'];
        $remaining_balance = $total_amount - $current_paid;

        if ( $payment_amount > $remaining_balance ) {
            $errors[] = "Payment amount exceeds remaining balance of {$remaining_balance}";
        }

        // Validate payment method
        $valid_methods = array( 'cash', 'credit_card', 'debit_card', 'bank_transfer', 'check', 'insurance' );
        if ( ! in_array( $payment_data['method'], $valid_methods ) ) {
            $errors[] = 'Invalid payment method';
        }

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

        return true;
    }

    private static function validate_finalization_requirements( $bill_id ) {
        $bill = Bill::get_by_id( $bill_id );
        $errors = array();

        // Check if bill has items or services
        $items = self::get_bill_items( $bill_id );
        if ( empty( $items ) && empty( $bill['description'] ) ) {
            $errors[] = 'Bill must have items or description before finalization';
        }

        // Check if total amount is positive
        if ( (float) $bill['total_amount'] <= 0 ) {
            $errors[] = 'Bill total amount must be positive';
        }

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

        return true;
    }

    private static function setup_bill_defaults( $bill_id, $bill_data ) {
        // Initialize bill items if provided
        if ( ! empty( $bill_data['items'] ) ) {
            self::save_bill_items( $bill_id, $bill_data['items'] );
        }

        // Setup payment tracking
        self::initialize_payment_tracking( $bill_id );

        // Create billing preferences
        self::setup_billing_preferences( $bill_id );
    }

    private static function handle_status_changes( $bill_id, $current_bill, $new_data ) {
        if ( isset( $new_data['status'] ) && $new_data['status'] != $current_bill['status'] ) {
            $status_change = array(
                'bill_id' => $bill_id,
                'from_status' => $current_bill['status'],
                'to_status' => $new_data['status'],
                'changed_by' => get_current_user_id(),
                'changed_at' => current_time( 'mysql' )
            );

            do_action( 'kivicare_bill_status_changed', $status_change );
        }
    }

    private static function handle_payment_updates( $bill_id, $current_bill, $new_data ) {
        // Log payment updates
        if ( isset( $new_data['amount_paid'] ) && $new_data['amount_paid'] != $current_bill['amount_paid'] ) {
            $payment_update = array(
                'bill_id' => $bill_id,
                'previous_paid' => $current_bill['amount_paid'],
                'new_paid' => $new_data['amount_paid'],
                'updated_by' => get_current_user_id(),
                'updated_at' => current_time( 'mysql' )
            );

            do_action( 'kivicare_bill_payment_updated', $payment_update );
        }
    }

    private static function record_payment_transaction( $bill_id, $payment_data ) {
        $transaction = array(
            'bill_id' => $bill_id,
            'amount' => $payment_data['amount'],
            'method' => $payment_data['method'],
            'reference' => $payment_data['reference'] ?? '',
            'notes' => $payment_data['notes'] ?? '',
            'processed_by' => get_current_user_id(),
            'processed_at' => current_time( 'mysql' )
        );

        // Store transaction
        $payments = get_option( "kivicare_bill_{$bill_id}_payments", array() );
        $payments[] = $transaction;
        update_option( "kivicare_bill_{$bill_id}_payments", $payments );
    }

    private static function send_payment_confirmation( $bill_id ) {
        // Send payment confirmation to patient
        do_action( 'kivicare_send_payment_confirmation', $bill_id );
    }

    private static function update_patient_account_balance( $patient_id ) {
        global $wpdb;
        
        // Calculate total outstanding balance for patient
        $balance = $wpdb->get_var(
            $wpdb->prepare(
                "SELECT SUM(total_amount - COALESCE(amount_paid, 0)) 
                 FROM {$wpdb->prefix}kc_bills 
                 WHERE patient_id = %d AND status NOT IN ('cancelled', 'refunded')",
                $patient_id
            )
        );

        // Update patient account balance
        update_option( "kivicare_patient_{$patient_id}_account_balance", $balance ?? 0 );
    }

    private static function generate_invoice_pdf( $bill_id ) {
        // Generate PDF invoice for the bill
        // This would typically use a PDF generation library
        do_action( 'kivicare_generate_invoice_pdf', $bill_id );
    }

    private static function send_bill_to_patient( $bill_id ) {
        // Send bill notification to patient
        do_action( 'kivicare_send_bill_notification', $bill_id );
    }

    // Helper methods for retrieving related data
    private static function get_bill_patient( $patient_id ) {
        global $wpdb;
        return $wpdb->get_row(
            $wpdb->prepare(
                "SELECT id, first_name, last_name, user_email, contact_no, address FROM {$wpdb->prefix}kc_patients WHERE id = %d",
                $patient_id
            ),
            ARRAY_A
        );
    }

    private static function get_bill_clinic( $clinic_id ) {
        global $wpdb;
        return $wpdb->get_row(
            $wpdb->prepare(
                "SELECT id, name, address, city, telephone_no, email FROM {$wpdb->prefix}kc_clinics WHERE id = %d",
                $clinic_id
            ),
            ARRAY_A
        );
    }

    private static function get_bill_appointment( $appointment_id ) {
        if ( ! $appointment_id ) return null;
        
        global $wpdb;
        return $wpdb->get_row(
            $wpdb->prepare(
                "SELECT id, appointment_number, appointment_start_date, appointment_start_time FROM {$wpdb->prefix}kc_appointments WHERE id = %d",
                $appointment_id
            ),
            ARRAY_A
        );
    }

    private static function get_bill_encounter( $encounter_id ) {
        if ( ! $encounter_id ) return null;
        
        global $wpdb;
        return $wpdb->get_row(
            $wpdb->prepare(
                "SELECT id, encounter_number, encounter_date, chief_complaint FROM {$wpdb->prefix}kc_encounters WHERE id = %d",
                $encounter_id
            ),
            ARRAY_A
        );
    }

    private static function get_bill_items( $bill_id ) {
        return get_option( "kivicare_bill_{$bill_id}_items", array() );
    }

    private static function get_bill_payments( $bill_id ) {
        return get_option( "kivicare_bill_{$bill_id}_payments", array() );
    }

    private static function is_bill_overdue( $bill ) {
        if ( in_array( $bill['status'], array( self::STATUS_PAID, self::STATUS_CANCELLED, self::STATUS_REFUNDED ) ) ) {
            return false;
        }
        
        return strtotime( $bill['due_date'] ) < time();
    }

    private static function get_days_overdue( $bill ) {
        if ( ! self::is_bill_overdue( $bill ) ) {
            return 0;
        }
        
        $due_date = new \DateTime( $bill['due_date'] );
        $today = new \DateTime();
        
        return $due_date->diff( $today )->days;
    }

    private static function save_bill_items( $bill_id, $items ) {
        update_option( "kivicare_bill_{$bill_id}_items", $items );
    }

    private static function initialize_payment_tracking( $bill_id ) {
        $tracking_data = array(
            'created_at' => current_time( 'mysql' ),
            'payment_reminders_sent' => 0,
            'last_reminder_date' => null
        );

        update_option( "kivicare_bill_{$bill_id}_tracking", $tracking_data );
    }

    private static function setup_billing_preferences( $bill_id ) {
        $preferences = array(
            'send_email_invoice' => true,
            'send_payment_reminders' => true,
            'reminder_days' => array( 7, 14, 30 )
        );

        update_option( "kivicare_bill_{$bill_id}_preferences", $preferences );
    }

    /**
     * Check for overdue bills (scheduled task)
     *
     * @since 1.0.0
     */
    public static function check_overdue_bills() {
        global $wpdb;

        // Update overdue bills
        $wpdb->query(
            "UPDATE {$wpdb->prefix}kc_bills 
             SET status = 'overdue' 
             WHERE due_date < CURDATE() 
             AND status = 'pending'"
        );

        // Get newly overdue bills
        $overdue_bills = $wpdb->get_results(
            "SELECT id FROM {$wpdb->prefix}kc_bills 
             WHERE status = 'overdue' 
             AND updated_at >= DATE_SUB(NOW(), INTERVAL 1 DAY)",
            ARRAY_A
        );

        // Trigger overdue actions
        foreach ( $overdue_bills as $bill ) {
            do_action( 'kivicare_bill_overdue', $bill['id'] );
        }
    }

    /**
     * Event handlers
     */
    public static function on_bill_created( $bill_id, $bill_data ) {
        error_log( "Care: New bill created - ID: {$bill_id}, Patient: " . ( $bill_data['patient_id'] ?? 'Unknown' ) );
    }

    public static function on_bill_updated( $bill_id, $bill_data ) {
        error_log( "Care: Bill updated - ID: {$bill_id}" );
        wp_cache_delete( "bill_{$bill_id}", 'kivicare' );
    }

    public static function on_bill_paid( $bill_id ) {
        error_log( "Care: Bill paid - ID: {$bill_id}" );
        wp_cache_delete( "bill_{$bill_id}", 'kivicare' );
        
        // Send thank you message
        do_action( 'kivicare_send_payment_thank_you', $bill_id );
    }

    public static function on_bill_overdue( $bill_id ) {
        error_log( "Care: Bill overdue - ID: {$bill_id}" );
        
        // Send overdue notice
        do_action( 'kivicare_send_overdue_notice', $bill_id );
    }
}