/**
 * Descomplicar® Crescimento Digital
 * https://descomplicar.pt
 */

<?php
/**
 * Integration tests for Automatic Billing Generation (User Story 4).
 * 
 * These tests validate complete user stories and MUST FAIL initially (TDD RED phase).
 *
 * @package Care_API\Tests\Integration
 */

/**
 * Billing automation integration tests.
 * 
 * User Story: Automatic billing generation based on encounters and services
 */
class Test_Billing_Automation extends Care_API_Test_Case {

	/**
	 * Test automatic billing generation workflow.
	 * 
	 * @test
	 */
	public function test_automatic_billing_generation_workflow() {
		// This test will fail initially as billing automation isn't implemented
		$this->markTestIncomplete( 'Automatic billing generation not implemented yet - TDD RED phase' );
		
		// ARRANGE: Setup complete billing scenario
		$clinic_id = $this->create_test_clinic();
		
		global $wpdb;
		
		// Create services with prices
		$service_ids = array();
		$services = array(
			array( 'name' => 'General Consultation', 'price' => '75.00', 'type' => 'consultation' ),
			array( 'name' => 'Blood Pressure Check', 'price' => '15.00', 'type' => 'procedure' ),
			array( 'name' => 'Prescription Review', 'price' => '25.00', 'type' => 'consultation' ),
		);
		
		foreach ( $services as $service ) {
			$wpdb->insert( $wpdb->prefix . 'kc_services', array(
				'name'       => $service['name'],
				'price'      => $service['price'],
				'type'       => $service['type'],
				'status'     => 1,
				'created_at' => current_time( 'mysql' ),
			));
			$service_ids[] = $wpdb->insert_id;
		}
		
		// Map doctor and patient to clinic
		$wpdb->insert( $wpdb->prefix . 'kc_doctor_clinic_mappings', array( 'doctor_id' => $this->doctor_user, 'clinic_id' => $clinic_id ) );
		$wpdb->insert( $wpdb->prefix . 'kc_patient_clinic_mappings', array( 'patient_id' => $this->patient_user, 'clinic_id' => $clinic_id ) );

		// STEP 1: Create appointment with services
		$appointment_data = array(
			'appointment_start_date' => gmdate( 'Y-m-d', strtotime( '+1 day' ) ),
			'appointment_start_time' => '14:30:00',
			'appointment_end_date'   => gmdate( 'Y-m-d', strtotime( '+1 day' ) ),
			'appointment_end_time'   => '15:30:00',
			'doctor_id'              => $this->doctor_user,
			'patient_id'             => $this->patient_user,
			'clinic_id'              => $clinic_id,
			'visit_type'             => 'consultation',
			'services'               => array( $service_ids[0], $service_ids[1] ), // Consultation + BP Check
		);

		$appointment_response = $this->make_request( '/wp-json/kivicare/v1/appointments', 'POST', $appointment_data, $this->receptionist_user );
		$this->assertRestResponse( $appointment_response, 201 );
		$appointment_id = $appointment_response->get_data()['id'];
		
		// Verify service mappings were created
		$service_mappings = $wpdb->get_results( 
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}kc_appointment_service_mapping WHERE appointment_id = %d", $appointment_id )
		);
		$this->assertCount( 2, $service_mappings );

		// STEP 2: Doctor creates encounter (this should trigger billing)
		$encounter_data = array(
			'appointment_id' => $appointment_id,
			'description'    => 'Patient consultation completed. Blood pressure checked and found to be within normal range.',
			'diagnosis'      => 'Routine health check - Normal findings',
			'treatment_plan' => 'Continue current lifestyle, return in 6 months',
			'status'         => 1,
		);

		$encounter_response = $this->make_request( '/wp-json/kivicare/v1/encounters', 'POST', $encounter_data, $this->doctor_user );
		$this->assertRestResponse( $encounter_response, 201 );
		$encounter_id = $encounter_response->get_data()['id'];

		// STEP 3: Verify automatic bill generation
		$bill = $wpdb->get_row( 
			$wpdb->prepare( 
				"SELECT * FROM {$wpdb->prefix}kc_bills WHERE encounter_id = %d AND appointment_id = %d",
				$encounter_id,
				$appointment_id
			)
		);
		
		$this->assertNotNull( $bill, 'Bill should be automatically generated when encounter is created' );
		$this->assertEquals( $encounter_id, $bill->encounter_id );
		$this->assertEquals( $appointment_id, $bill->appointment_id );
		$this->assertEquals( $clinic_id, $bill->clinic_id );
		$this->assertEquals( 'unpaid', $bill->payment_status );

		// STEP 4: Verify bill amount calculation
		$expected_total = 75.00 + 15.00; // Consultation + BP Check
		$this->assertEquals( number_format( $expected_total, 2 ), $bill->total_amount );
		$this->assertEquals( '0.00', $bill->discount );
		$this->assertEquals( number_format( $expected_total, 2 ), $bill->actual_amount );

		// STEP 5: Doctor adds additional service during encounter
		$additional_service_response = $this->make_request( 
			"/wp-json/kivicare/v1/encounters/{$encounter_id}/services", 
			'POST', 
			array( 'service_id' => $service_ids[2] ), // Prescription Review
			$this->doctor_user 
		);
		$this->assertRestResponse( $additional_service_response, 201 );

		// STEP 6: Verify bill was automatically updated
		$updated_bill = $wpdb->get_row( 
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}kc_bills WHERE id = %d", $bill->id )
		);
		
		$new_expected_total = $expected_total + 25.00; // Added Prescription Review
		$this->assertEquals( number_format( $new_expected_total, 2 ), $updated_bill->total_amount );
		$this->assertEquals( number_format( $new_expected_total, 2 ), $updated_bill->actual_amount );

		// STEP 7: Test bill retrieval via API
		$bill_response = $this->make_request( "/wp-json/kivicare/v1/bills/{$bill->id}", 'GET', array(), $this->receptionist_user );
		$this->assertRestResponse( $bill_response, 200 );
		
		$bill_data = $bill_response->get_data();
		$this->assertEquals( $bill->id, $bill_data['id'] );
		$this->assertEquals( $encounter_id, $bill_data['encounter_id'] );
		$this->assertEquals( number_format( $new_expected_total, 2 ), $bill_data['total_amount'] );
		
		// Verify bill includes service breakdown
		$this->assertArrayHasKey( 'services', $bill_data );
		$this->assertCount( 3, $bill_data['services'] );

		// STEP 8: Test payment processing
		$payment_data = array(
			'amount'         => $bill_data['actual_amount'],
			'payment_method' => 'cash',
			'notes'          => 'Payment received in full',
		);

		$payment_response = $this->make_request( "/wp-json/kivicare/v1/bills/{$bill->id}/payment", 'POST', $payment_data, $this->receptionist_user );
		$this->assertRestResponse( $payment_response, 200 );
		
		// Verify payment status updated
		$paid_bill = $wpdb->get_row( 
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}kc_bills WHERE id = %d", $bill->id )
		);
		$this->assertEquals( 'paid', $paid_bill->payment_status );
	}

	/**
	 * Test billing with discounts and insurance.
	 * 
	 * @test
	 */
	public function test_billing_with_discounts_and_insurance() {
		// This test will fail initially as discount/insurance features aren't implemented
		$this->markTestIncomplete( 'Billing discounts and insurance not implemented yet - TDD RED phase' );
		
		// ARRANGE: Setup scenario with discounts
		$clinic_id = $this->create_test_clinic();
		$appointment_id = $this->create_test_appointment( $clinic_id, $this->doctor_user, $this->patient_user );
		
		// Create encounter
		$encounter_response = $this->make_request( '/wp-json/kivicare/v1/encounters', 'POST', array(
			'appointment_id' => $appointment_id,
			'description'    => 'Test encounter for billing with discounts',
		), $this->doctor_user );
		
		$encounter_id = $encounter_response->get_data()['id'];

		// STEP 1: Apply senior citizen discount (20%)
		$discount_data = array(
			'type'        => 'percentage',
			'value'       => 20,
			'reason'      => 'Senior citizen discount',
			'applied_by'  => $this->doctor_user,
		);

		$discount_response = $this->make_request( "/wp-json/kivicare/v1/bills/encounter/{$encounter_id}/discount", 'POST', $discount_data, $this->doctor_user );
		$this->assertRestResponse( $discount_response, 200 );

		// STEP 2: Verify discount was applied to bill
		global $wpdb;
		$bill = $wpdb->get_row( 
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}kc_bills WHERE encounter_id = %d", $encounter_id )
		);
		
		$total_amount = floatval( $bill->total_amount );
		$discount_amount = floatval( $bill->discount );
		$actual_amount = floatval( $bill->actual_amount );
		
		$this->assertEquals( $total_amount * 0.20, $discount_amount );
		$this->assertEquals( $total_amount - $discount_amount, $actual_amount );

		// STEP 3: Test insurance claim processing
		$insurance_data = array(
			'insurance_provider' => 'Medicare',
			'policy_number'      => 'POL123456789',
			'coverage_percentage' => 80,
			'claim_amount'       => $actual_amount,
		);

		$insurance_response = $this->make_request( "/wp-json/kivicare/v1/bills/{$bill->id}/insurance", 'POST', $insurance_data, $this->receptionist_user );
		$this->assertRestResponse( $insurance_response, 201 );
		
		// Verify insurance claim was created
		$claim = $wpdb->get_row( 
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}kc_insurance_claims WHERE bill_id = %d", $bill->id )
		);
		$this->assertNotNull( $claim );
		$this->assertEquals( 'pending', $claim->status );
	}

	/**
	 * Test billing error handling and edge cases.
	 * 
	 * @test
	 */
	public function test_billing_error_handling() {
		// This test will fail initially as error handling isn't implemented
		$this->markTestIncomplete( 'Billing error handling not implemented yet - TDD RED phase' );
		
		$clinic_id = $this->create_test_clinic();
		
		// Test error scenarios
		$error_tests = array(
			// Encounter without appointment
			array(
				'scenario' => 'Encounter without appointment',
				'setup'    => function() {
					return array(
						'description' => 'Test encounter without appointment',
						'patient_id'  => $this->patient_user,
						'clinic_id'   => $this->create_test_clinic(),
					);
				},
				'expected_error' => 'missing_appointment',
			),
			// Appointment without services
			array(
				'scenario' => 'Appointment without services',
				'setup'    => function() use ( $clinic_id ) {
					$appointment_id = $this->create_test_appointment( $clinic_id, $this->doctor_user, $this->patient_user );
					// Clear any default services
					global $wpdb;
					$wpdb->delete( $wpdb->prefix . 'kc_appointment_service_mapping', array( 'appointment_id' => $appointment_id ) );
					
					return array(
						'appointment_id' => $appointment_id,
						'description'    => 'Test encounter without services',
					);
				},
				'expected_error' => 'no_billable_services',
			),
		);

		foreach ( $error_tests as $test ) {
			$encounter_data = $test['setup']();
			
			$response = $this->make_request( '/wp-json/kivicare/v1/encounters', 'POST', $encounter_data, $this->doctor_user );
			
			// Should either prevent encounter creation or generate appropriate billing warning
			if ( $response->get_status() === 201 ) {
				// If encounter was created, check for billing warnings
				$encounter = $response->get_data();
				$this->assertArrayHasKey( 'billing_warnings', $encounter );
			} else {
				// If encounter was prevented, check error code
				$error_data = $response->get_data();
				$this->assertEquals( $test['expected_error'], $error_data['code'] );
			}
		}
	}

	/**
	 * Test billing permissions and access control.
	 * 
	 * @test
	 */
	public function test_billing_permissions() {
		// This test will fail initially as billing permissions aren't implemented
		$this->markTestIncomplete( 'Billing permissions not implemented yet - TDD RED phase' );
		
		// ARRANGE: Create bill
		$clinic_id = $this->create_test_clinic();
		$appointment_id = $this->create_test_appointment( $clinic_id, $this->doctor_user, $this->patient_user );
		
		$encounter_response = $this->make_request( '/wp-json/kivicare/v1/encounters', 'POST', array(
			'appointment_id' => $appointment_id,
			'description'    => 'Test encounter for billing permissions',
		), $this->doctor_user );
		
		$encounter_id = $encounter_response->get_data()['id'];
		
		global $wpdb;
		$bill = $wpdb->get_row( 
			$wpdb->prepare( "SELECT * FROM {$wpdb->prefix}kc_bills WHERE encounter_id = %d", $encounter_id )
		);

		// Test role-based permissions
		$permission_tests = array(
			// View bill permissions
			array( 'action' => 'GET', 'endpoint' => "/wp-json/kivicare/v1/bills/{$bill->id}", 'user' => $this->admin_user, 'expected' => 200 ),
			array( 'action' => 'GET', 'endpoint' => "/wp-json/kivicare/v1/bills/{$bill->id}", 'user' => $this->doctor_user, 'expected' => 200 ),
			array( 'action' => 'GET', 'endpoint' => "/wp-json/kivicare/v1/bills/{$bill->id}", 'user' => $this->receptionist_user, 'expected' => 200 ),
			array( 'action' => 'GET', 'endpoint' => "/wp-json/kivicare/v1/bills/{$bill->id}", 'user' => $this->patient_user, 'expected' => 200 ), // Own bill
			
			// Payment processing permissions
			array( 'action' => 'POST', 'endpoint' => "/wp-json/kivicare/v1/bills/{$bill->id}/payment", 'user' => $this->receptionist_user, 'expected' => 200 ),
			array( 'action' => 'POST', 'endpoint' => "/wp-json/kivicare/v1/bills/{$bill->id}/payment", 'user' => $this->admin_user, 'expected' => 200 ),
			array( 'action' => 'POST', 'endpoint' => "/wp-json/kivicare/v1/bills/{$bill->id}/payment", 'user' => $this->doctor_user, 'expected' => 403 ), // Doctor cannot process payments
			array( 'action' => 'POST', 'endpoint' => "/wp-json/kivicare/v1/bills/{$bill->id}/payment", 'user' => $this->patient_user, 'expected' => 403 ), // Patient cannot process payments
		);

		foreach ( $permission_tests as $test ) {
			$data = ( $test['action'] === 'POST' ) ? array( 'amount' => $bill->actual_amount, 'payment_method' => 'cash' ) : array();
			
			$response = $this->make_request( $test['endpoint'], $test['action'], $data, $test['user'] );
			$this->assertRestResponse( $response, $test['expected'] );
		}
	}

	/**
	 * Test billing reports and analytics.
	 * 
	 * @test
	 */
	public function test_billing_reports_and_analytics() {
		// This test will fail initially as billing reports aren't implemented
		$this->markTestIncomplete( 'Billing reports not implemented yet - TDD RED phase' );
		
		// ARRANGE: Create multiple bills with different statuses
		$clinic_id = $this->create_test_clinic();
		
		$bill_scenarios = array(
			array( 'amount' => 100.00, 'status' => 'paid', 'date' => '2024-01-15' ),
			array( 'amount' => 150.00, 'status' => 'unpaid', 'date' => '2024-01-16' ),
			array( 'amount' => 75.00, 'status' => 'paid', 'date' => '2024-01-17' ),
			array( 'amount' => 200.00, 'status' => 'partially_paid', 'date' => '2024-01-18' ),
		);

		foreach ( $bill_scenarios as $scenario ) {
			$appointment_id = $this->create_test_appointment( $clinic_id, $this->doctor_user, $this->patient_user );
			
			$encounter_response = $this->make_request( '/wp-json/kivicare/v1/encounters', 'POST', array(
				'appointment_id' => $appointment_id,
				'description'    => 'Test encounter for billing reports',
				'encounter_date' => $scenario['date'],
			), $this->doctor_user );
			
			// Simulate different payment statuses
			global $wpdb;
			$encounter_id = $encounter_response->get_data()['id'];
			$wpdb->update( 
				$wpdb->prefix . 'kc_bills',
				array( 
					'total_amount'    => number_format( $scenario['amount'], 2 ),
					'actual_amount'   => number_format( $scenario['amount'], 2 ),
					'payment_status'  => $scenario['status'],
				),
				array( 'encounter_id' => $encounter_id )
			);
		}

		// ACT: Generate billing reports
		$reports_response = $this->make_request( '/wp-json/kivicare/v1/reports/billing', 'GET', array(
			'start_date' => '2024-01-01',
			'end_date'   => '2024-01-31',
			'clinic_id'  => $clinic_id,
		), $this->admin_user );

		// ASSERT: Report contains expected data
		$this->assertRestResponse( $reports_response, 200 );
		
		$report = $reports_response->get_data();
		$this->assertArrayHasKey( 'total_revenue', $report );
		$this->assertArrayHasKey( 'outstanding_amount', $report );
		$this->assertArrayHasKey( 'payment_summary', $report );
		
		// Verify calculations
		$this->assertEquals( 525.00, $report['total_billed'] ); // Sum of all bills
		$this->assertEquals( 175.00, $report['total_revenue'] ); // Only paid bills
		$this->assertEquals( 350.00, $report['outstanding_amount'] ); // Unpaid + partially paid
	}
}