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

<?php
/**
 * Contract tests for Patient endpoints.
 * 
 * These tests define the API contract and MUST FAIL initially (TDD RED phase).
 *
 * @package Care_API\Tests\Contract
 */

/**
 * Patient endpoints contract tests.
 */
class Test_Patient_Endpoints_Contract extends Care_API_Test_Case {

	/**
	 * Test GET /wp-json/care/v1/patients endpoint contract.
	 * 
	 * @test
	 */
	public function test_get_patients_endpoint_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Patients GET endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Authenticated doctor
		wp_set_current_user( $this->doctor_user );

		// ACT: Make GET request to patients endpoint
		$response = $this->make_request( '/wp-json/care/v1/patients' );

		// ASSERT: Response contract
		$this->assertRestResponse( $response, 200 );
		
		$data = $response->get_data();
		$this->assertIsArray( $data );
		
		// Validate pagination structure
		if ( ! empty( $data ) ) {
			$this->assertArrayHasKey( 'data', $data );
			$this->assertArrayHasKey( 'total', $data );
			$this->assertArrayHasKey( 'page', $data );
			$this->assertArrayHasKey( 'per_page', $data );
			
			// Validate patient data structure
			$patient = $data['data'][0];
			$this->assertPatientStructure( $patient );
		}
	}

	/**
	 * Test POST /wp-json/care/v1/patients endpoint contract.
	 * 
	 * @test
	 */
	public function test_create_patient_endpoint_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Patients POST endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Valid patient data
		$patient_data = array(
			'display_name' => 'João Silva Santos',
			'user_email'   => 'joao.santos@example.com',
			'clinic_id'    => $this->create_test_clinic(),
			'first_name'   => 'João',
			'last_name'    => 'Santos',
			'phone'        => '+351912345678',
			'address'      => 'Rua das Flores, 123',
			'city'         => 'Lisboa',
			'postal_code'  => '1000-001',
			'birth_date'   => '1985-05-15',
			'gender'       => 'M',
		);

		// ACT: Make POST request as doctor
		$response = $this->make_request( '/wp-json/care/v1/patients', 'POST', $patient_data, $this->doctor_user );

		// ASSERT: Response contract
		$this->assertRestResponse( $response, 201 );
		
		$data = $response->get_data();
		$this->assertPatientStructure( $data );
		$this->assertEquals( $patient_data['display_name'], $data['display_name'] );
		$this->assertEquals( $patient_data['user_email'], $data['user_email'] );
		$this->assertIsInt( $data['id'] );
		$this->assertGreaterThan( 0, $data['id'] );
	}

	/**
	 * Test POST /wp-json/care/v1/patients with invalid data.
	 * 
	 * @test
	 */
	public function test_create_patient_invalid_data() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Patients POST validation not implemented yet - TDD RED phase' );
		
		// ARRANGE: Invalid patient data
		$invalid_data = array(
			'display_name' => '', // Empty name should fail
			'user_email'   => 'invalid-email', // Invalid email format
			'clinic_id'    => 'not_a_number', // Invalid clinic ID
		);

		// ACT: Make POST request with invalid data
		$response = $this->make_request( '/wp-json/care/v1/patients', 'POST', $invalid_data, $this->doctor_user );

		// ASSERT: Validation error contract
		$this->assertRestResponse( $response, 400 );
		
		$data = $response->get_data();
		$this->assertArrayHasKey( 'code', $data );
		$this->assertEquals( 'rest_invalid_param', $data['code'] );
		$this->assertArrayHasKey( 'data', $data );
		$this->assertArrayHasKey( 'params', $data['data'] );
	}

	/**
	 * Test GET /wp-json/care/v1/patients/{id} endpoint contract.
	 * 
	 * @test
	 */
	public function test_get_patient_by_id_endpoint_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Patient by ID endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Existing patient
		$patient_id = $this->patient_user;

		// ACT: Make GET request for specific patient
		$response = $this->make_request( "/wp-json/care/v1/patients/{$patient_id}", 'GET', array(), $this->doctor_user );

		// ASSERT: Response contract
		$this->assertRestResponse( $response, 200 );
		
		$data = $response->get_data();
		$this->assertPatientStructure( $data );
		$this->assertEquals( $patient_id, $data['id'] );
	}

	/**
	 * Test PUT /wp-json/care/v1/patients/{id} endpoint contract.
	 * 
	 * @test
	 */
	public function test_update_patient_endpoint_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Patient PUT endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Existing patient and update data
		$patient_id = $this->patient_user;
		$update_data = array(
			'phone'   => '+351987654321',
			'address' => 'Nova Morada, 456',
		);

		// ACT: Make PUT request to update patient
		$response = $this->make_request( "/wp-json/care/v1/patients/{$patient_id}", 'PUT', $update_data, $this->doctor_user );

		// ASSERT: Response contract
		$this->assertRestResponse( $response, 200 );
		
		$data = $response->get_data();
		$this->assertPatientStructure( $data );
		$this->assertEquals( $update_data['phone'], $data['phone'] );
	}

	/**
	 * Test GET /wp-json/care/v1/patients/{id}/encounters endpoint contract.
	 * 
	 * @test
	 */
	public function test_get_patient_encounters_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Patient encounters endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Patient with encounters
		$patient_id = $this->patient_user;
		$clinic_id = $this->create_test_clinic();
		$appointment_id = $this->create_test_appointment( $clinic_id, $this->doctor_user, $patient_id );

		// ACT: Make GET request for patient encounters
		$response = $this->make_request( "/wp-json/care/v1/patients/{$patient_id}/encounters", 'GET', array(), $this->doctor_user );

		// ASSERT: Response contract
		$this->assertRestResponse( $response, 200 );
		
		$data = $response->get_data();
		$this->assertIsArray( $data );
		
		if ( ! empty( $data ) ) {
			$encounter = $data[0];
			$this->assertEncounterStructure( $encounter );
			$this->assertEquals( $patient_id, $encounter['patient_id'] );
		}
	}

	/**
	 * Test GET /wp-json/care/v1/patients/{id}/prescriptions endpoint contract.
	 * 
	 * @test
	 */
	public function test_get_patient_prescriptions_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Patient prescriptions endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Patient with prescriptions
		$patient_id = $this->patient_user;

		// ACT: Make GET request for patient prescriptions
		$response = $this->make_request( "/wp-json/care/v1/patients/{$patient_id}/prescriptions", 'GET', array(), $this->doctor_user );

		// ASSERT: Response contract
		$this->assertRestResponse( $response, 200 );
		
		$data = $response->get_data();
		$this->assertIsArray( $data );
		
		if ( ! empty( $data ) ) {
			$prescription = $data[0];
			$this->assertPrescriptionStructure( $prescription );
			$this->assertEquals( $patient_id, $prescription['patient_id'] );
		}
	}

	/**
	 * Test patient privacy and data access restrictions.
	 * 
	 * @test
	 */
	public function test_patient_privacy_contract() {
		// This test will fail initially as privacy controls aren't implemented
		$this->markTestIncomplete( 'Patient privacy controls not implemented yet - TDD RED phase' );
		
		// ARRANGE: Two different patients
		$patient1_id = $this->patient_user;
		$patient2_id = $this->factory->user->create( array( 'role' => 'patient' ) );

		// ACT & ASSERT: Patient should only see their own data
		$response = $this->make_request( "/wp-json/care/v1/patients/{$patient1_id}", 'GET', array(), $patient1_id );
		$this->assertRestResponse( $response, 200 );

		// ACT & ASSERT: Patient should not see other patient's data
		$response = $this->make_request( "/wp-json/care/v1/patients/{$patient2_id}", 'GET', array(), $patient1_id );
		$this->assertRestResponse( $response, 403 );
	}

	/**
	 * Helper method to assert patient data structure.
	 *
	 * @param array $patient Patient data to validate.
	 */
	private function assertPatientStructure( $patient ) {
		$this->assertIsArray( $patient );
		
		// Required fields from wp_users
		$this->assertArrayHasKey( 'id', $patient );
		$this->assertArrayHasKey( 'display_name', $patient );
		$this->assertArrayHasKey( 'user_email', $patient );
		
		// Additional patient fields
		$expected_fields = array(
			'first_name', 'last_name', 'phone', 'address',
			'city', 'postal_code', 'birth_date', 'gender',
			'clinic_id', 'registration_date'
		);
		
		foreach ( $expected_fields as $field ) {
			$this->assertArrayHasKey( $field, $patient );
		}
		
		// Data type validations
		$this->assertIsInt( $patient['id'] );
		$this->assertIsString( $patient['display_name'] );
		$this->assertIsString( $patient['user_email'] );
		
		if ( ! empty( $patient['clinic_id'] ) ) {
			$this->assertIsInt( $patient['clinic_id'] );
		}
	}

	/**
	 * Helper method to assert encounter data structure.
	 *
	 * @param array $encounter Encounter data to validate.
	 */
	private function assertEncounterStructure( $encounter ) {
		$this->assertIsArray( $encounter );
		
		$expected_fields = array(
			'id', 'encounter_date', 'patient_id', 'doctor_id',
			'clinic_id', 'appointment_id', 'description', 'status'
		);
		
		foreach ( $expected_fields as $field ) {
			$this->assertArrayHasKey( $field, $encounter );
		}
		
		$this->assertIsInt( $encounter['id'] );
		$this->assertIsInt( $encounter['patient_id'] );
		$this->assertIsInt( $encounter['doctor_id'] );
	}

	/**
	 * Helper method to assert prescription data structure.
	 *
	 * @param array $prescription Prescription data to validate.
	 */
	private function assertPrescriptionStructure( $prescription ) {
		$this->assertIsArray( $prescription );
		
		$expected_fields = array(
			'id', 'encounter_id', 'patient_id', 'name',
			'frequency', 'duration', 'instruction'
		);
		
		foreach ( $expected_fields as $field ) {
			$this->assertArrayHasKey( $field, $prescription );
		}
		
		$this->assertIsInt( $prescription['id'] );
		$this->assertIsInt( $prescription['patient_id'] );
		$this->assertIsString( $prescription['name'] );
	}
}