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

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

/**
 * Appointment endpoints contract tests.
 */
class Test_Appointment_Endpoints_Contract extends Care_API_Test_Case {

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

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

		// 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 appointment data structure
			$appointment = $data['data'][0];
			$this->assertAppointmentStructure( $appointment );
		}
	}

	/**
	 * Test POST /wp-json/care/v1/appointments endpoint contract.
	 * 
	 * @test
	 */
	public function test_create_appointment_endpoint_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Appointments POST endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Valid appointment data
		$clinic_id = $this->create_test_clinic();
		$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:00:00',
			'doctor_id'              => $this->doctor_user,
			'patient_id'             => $this->patient_user,
			'clinic_id'              => $clinic_id,
			'visit_type'             => 'consultation',
			'description'            => 'Consulta de rotina',
		);

		// ACT: Make POST request as receptionist
		$response = $this->make_request( '/wp-json/care/v1/appointments', 'POST', $appointment_data, $this->receptionist_user );

		// ASSERT: Response contract
		$this->assertRestResponse( $response, 201 );
		
		$data = $response->get_data();
		$this->assertAppointmentStructure( $data );
		$this->assertEquals( $appointment_data['doctor_id'], $data['doctor_id'] );
		$this->assertEquals( $appointment_data['patient_id'], $data['patient_id'] );
		$this->assertIsInt( $data['id'] );
		$this->assertGreaterThan( 0, $data['id'] );
	}

	/**
	 * Test POST /wp-json/care/v1/appointments with scheduling conflict.
	 * 
	 * @test
	 */
	public function test_create_appointment_time_conflict() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Appointment time conflict validation not implemented yet - TDD RED phase' );
		
		// ARRANGE: Existing appointment and conflicting data
		$clinic_id = $this->create_test_clinic();
		$existing_appointment = $this->create_test_appointment( $clinic_id, $this->doctor_user, $this->patient_user );
		
		$conflicting_data = array(
			'appointment_start_date' => gmdate( 'Y-m-d', strtotime( '+1 day' ) ),
			'appointment_start_time' => '14:45:00', // Conflicts with existing 14:30-15:00
			'appointment_end_date'   => gmdate( 'Y-m-d', strtotime( '+1 day' ) ),
			'appointment_end_time'   => '15:15:00',
			'doctor_id'              => $this->doctor_user,
			'patient_id'             => $this->factory->user->create( array( 'role' => 'patient' ) ),
			'clinic_id'              => $clinic_id,
			'visit_type'             => 'consultation',
		);

		// ACT: Make POST request with conflicting time
		$response = $this->make_request( '/wp-json/care/v1/appointments', 'POST', $conflicting_data, $this->receptionist_user );

		// ASSERT: Time conflict error contract
		$this->assertRestResponse( $response, 409 );
		
		$data = $response->get_data();
		$this->assertArrayHasKey( 'code', $data );
		$this->assertEquals( 'appointment_time_conflict', $data['code'] );
	}

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

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

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

	/**
	 * Test PUT /wp-json/care/v1/appointments/{id} endpoint contract.
	 * 
	 * @test
	 */
	public function test_update_appointment_endpoint_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Appointment PUT endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Existing appointment and update data
		$clinic_id = $this->create_test_clinic();
		$appointment_id = $this->create_test_appointment( $clinic_id, $this->doctor_user, $this->patient_user );
		$update_data = array(
			'appointment_start_time' => '15:30:00',
			'appointment_end_time'   => '16:00:00',
			'description'            => 'Updated appointment description',
		);

		// ACT: Make PUT request to update appointment
		$response = $this->make_request( "/wp-json/care/v1/appointments/{$appointment_id}", 'PUT', $update_data, $this->receptionist_user );

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

	/**
	 * Test DELETE /wp-json/care/v1/appointments/{id} endpoint contract.
	 * 
	 * @test
	 */
	public function test_delete_appointment_endpoint_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Appointment DELETE endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Existing appointment
		$clinic_id = $this->create_test_clinic();
		$appointment_id = $this->create_test_appointment( $clinic_id, $this->doctor_user, $this->patient_user );

		// ACT: Make DELETE request
		$response = $this->make_request( "/wp-json/care/v1/appointments/{$appointment_id}", 'DELETE', array(), $this->receptionist_user );

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

	/**
	 * Test GET /wp-json/care/v1/appointments/available-slots endpoint contract.
	 * 
	 * @test
	 */
	public function test_get_available_slots_contract() {
		// This test will fail initially as the endpoint doesn't exist yet
		$this->markTestIncomplete( 'Available slots endpoint not implemented yet - TDD RED phase' );
		
		// ARRANGE: Query parameters for slot availability
		$query_params = array(
			'doctor_id' => $this->doctor_user,
			'date'      => gmdate( 'Y-m-d', strtotime( '+1 day' ) ),
			'clinic_id' => $this->create_test_clinic(),
		);

		// ACT: Make GET request for available slots
		$response = $this->make_request( '/wp-json/care/v1/appointments/available-slots', 'GET', $query_params );

		// ASSERT: Response contract
		$this->assertRestResponse( $response, 200 );
		
		$data = $response->get_data();
		$this->assertIsArray( $data );
		$this->assertArrayHasKey( 'date', $data );
		$this->assertArrayHasKey( 'doctor_id', $data );
		$this->assertArrayHasKey( 'available_slots', $data );
		
		// Validate slot structure
		if ( ! empty( $data['available_slots'] ) ) {
			$slot = $data['available_slots'][0];
			$this->assertArrayHasKey( 'start_time', $slot );
			$this->assertArrayHasKey( 'end_time', $slot );
			$this->assertArrayHasKey( 'available', $slot );
		}
	}

	/**
	 * Test appointment filtering and search capabilities.
	 * 
	 * @test
	 */
	public function test_appointment_filtering_contract() {
		// This test will fail initially as filtering isn't implemented
		$this->markTestIncomplete( 'Appointment filtering not implemented yet - TDD RED phase' );
		
		// ARRANGE: Multiple appointments with different attributes
		$clinic_id = $this->create_test_clinic();
		
		// ACT: Test date filtering
		$filter_params = array(
			'start_date' => gmdate( 'Y-m-d' ),
			'end_date'   => gmdate( 'Y-m-d', strtotime( '+7 days' ) ),
		);
		$response = $this->make_request( '/wp-json/care/v1/appointments', 'GET', $filter_params, $this->doctor_user );

		// ASSERT: Filtered response contract
		$this->assertRestResponse( $response, 200 );
		
		// ACT: Test doctor filtering
		$filter_params = array( 'doctor_id' => $this->doctor_user );
		$response = $this->make_request( '/wp-json/care/v1/appointments', 'GET', $filter_params, $this->admin_user );

		// ASSERT: Doctor-filtered response contract
		$this->assertRestResponse( $response, 200 );
	}

	/**
	 * Helper method to assert appointment data structure.
	 *
	 * @param array $appointment Appointment data to validate.
	 */
	private function assertAppointmentStructure( $appointment ) {
		$this->assertIsArray( $appointment );
		
		// Required fields
		$expected_fields = array(
			'id', 'appointment_start_date', 'appointment_start_time',
			'appointment_end_date', 'appointment_end_time', 'doctor_id',
			'patient_id', 'clinic_id', 'status', 'visit_type', 'created_at'
		);
		
		foreach ( $expected_fields as $field ) {
			$this->assertArrayHasKey( $field, $appointment );
		}
		
		// Data type validations
		$this->assertIsInt( $appointment['id'] );
		$this->assertIsInt( $appointment['doctor_id'] );
		$this->assertIsInt( $appointment['patient_id'] );
		$this->assertIsInt( $appointment['clinic_id'] );
		$this->assertIsInt( $appointment['status'] );
		
		// Date/time format validations
		$this->assertMatchesRegularExpression( '/^\d{4}-\d{2}-\d{2}$/', $appointment['appointment_start_date'] );
		$this->assertMatchesRegularExpression( '/^\d{2}:\d{2}:\d{2}$/', $appointment['appointment_start_time'] );
		
		// Optional fields that might be present
		$optional_fields = array( 'description', 'patient', 'doctor', 'clinic' );
		
		// If expanded data is included, validate structure
		if ( isset( $appointment['patient'] ) ) {
			$this->assertIsArray( $appointment['patient'] );
			$this->assertArrayHasKey( 'display_name', $appointment['patient'] );
		}
		
		if ( isset( $appointment['doctor'] ) ) {
			$this->assertIsArray( $appointment['doctor'] );
			$this->assertArrayHasKey( 'display_name', $appointment['doctor'] );
		}
	}
}