<?php
/**
 * AEAT Test Scenarios
 *
 * Test scenarios for verifying the AEAT error handling layer.
 * These can be used to simulate different AEAT responses without making real API calls.
 *
 * @package Freefactu
 * @since 1.1.0
 */

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

/**
 * Class Freefactu_Aeat_Test_Scenarios
 *
 * Provides mock AEAT responses for testing the error handling layer.
 * Can be used from WP-CLI, admin page, or unit tests.
 */
class Freefactu_Aeat_Test_Scenarios {

	/**
	 * Get all available test scenarios.
	 *
	 * @return array Array of scenario definitions.
	 */
	public static function get_all_scenarios() {
		return array(
			'success' => array(
				'name'        => 'Successful Submission',
				'description' => 'Invoice accepted by AEAT without errors.',
				'expected'    => array(
					'status'      => 'accepted',
					'next_action' => Freefactu_Aeat_Next_Action::NO_ACTION_NEEDED,
				),
			),
			'census_error' => array(
				'name'        => 'Census Error (Subsanable)',
				'description' => 'NIF not found in AEAT census. Can be fixed by correcting NIF.',
				'expected'    => array(
					'status'         => 'rejected',
					'error_category' => Freefactu_Aeat_Error_Categories::CENSUS,
					'next_action'    => Freefactu_Aeat_Next_Action::RETRY_SUBSANATION,
				),
			),
			'xml_error' => array(
				'name'        => 'XML Format Error (Subsanable)',
				'description' => 'XML does not validate against XSD.',
				'expected'    => array(
					'status'         => 'rejected',
					'error_category' => Freefactu_Aeat_Error_Categories::XML_FORMAT,
					'next_action'    => Freefactu_Aeat_Next_Action::RETRY_SUBSANATION,
				),
			),
			'hash_error' => array(
				'name'        => 'Hash Chain Error',
				'description' => 'Hash does not match expected value.',
				'expected'    => array(
					'status'         => 'rejected',
					'error_category' => Freefactu_Aeat_Error_Categories::HASH_CHAIN,
					'next_action'    => Freefactu_Aeat_Next_Action::RETRY_SUBSANATION,
				),
			),
			'f2_rejection' => array(
				'name'        => 'F2 Cancellation Rejected',
				'description' => 'Cancellation request rejected. Must send new F2.',
				'invoice_type' => 'F2',
				'expected'    => array(
					'status'      => 'rejected',
					'next_action' => Freefactu_Aeat_Next_Action::RETRY_NEW_F2,
				),
			),
			'business_error' => array(
				'name'        => 'Business Content Error',
				'description' => 'VAT type incorrect. Requires rectificativa.',
				'expected'    => array(
					'status'         => 'rejected',
					'error_category' => Freefactu_Aeat_Error_Categories::BUSINESS,
					'next_action'    => Freefactu_Aeat_Next_Action::CREATE_RECTIFICATIVA,
				),
			),
			'max_attempts' => array(
				'name'        => 'Max Subsanation Attempts Reached',
				'description' => 'Already tried subsanation 3 times. Manual intervention needed.',
				'setup'       => array( 'subsanation_count' => 3 ),
				'expected'    => array(
					'status'      => 'rejected',
					'next_action' => Freefactu_Aeat_Next_Action::MANUAL_INTERVENTION,
				),
			),
			'already_accepted' => array(
				'name'        => 'Already Accepted Invoice',
				'description' => 'Invoice was accepted. Cannot subsanar, must use rectificativa.',
				'setup'       => array( 'aeat_final_status' => 'accepted' ),
				'expected'    => array(
					'next_action' => Freefactu_Aeat_Next_Action::CREATE_RECTIFICATIVA,
				),
			),
		);
	}

	/**
	 * Create a mock Freefactu_Aeat_Response for a scenario.
	 *
	 * @param string $scenario_key Scenario key from get_all_scenarios().
	 * @return Freefactu_Aeat_Response
	 */
	public static function create_mock_response( $scenario_key ) {
		switch ( $scenario_key ) {
			case 'success':
				return Freefactu_Aeat_Response::success( 'CSV-' . time() . '-' . wp_rand( 1000, 9999 ) );

			case 'census_error':
				return Freefactu_Aeat_Response::rejected(
					'1100',
					'El NIF del destinatario no está dado de alta en el censo de la AEAT.'
				);

			case 'xml_error':
				return Freefactu_Aeat_Response::rejected(
					'2002',
					'El contenido del elemento no es válido según el esquema XSD.'
				);

			case 'hash_error':
				return Freefactu_Aeat_Response::rejected(
					'3001',
					'La huella digital no coincide con el valor esperado.'
				);

			case 'f2_rejection':
				return Freefactu_Aeat_Response::rejected(
					'4004',
					'No existe el registro de facturación que se pretende anular.'
				);

			case 'business_error':
				return Freefactu_Aeat_Response::rejected(
					'6001',
					'El tipo impositivo de IVA no es válido para esta operación.'
				);

			case 'max_attempts':
			case 'already_accepted':
				// These need setup, not different response
				return Freefactu_Aeat_Response::rejected(
					'1100',
					'El NIF del destinatario no está dado de alta en el censo de la AEAT.'
				);

			default:
				return Freefactu_Aeat_Response::rejected( '9999', 'Unknown test scenario' );
		}
	}

	/**
	 * Create mock invoice data for a scenario.
	 *
	 * @param string $scenario_key Scenario key.
	 * @param int    $order_id     Optional order ID.
	 * @return array Invoice data array.
	 */
	public static function create_mock_invoice_data( $scenario_key, $order_id = 12345 ) {
		$scenarios = self::get_all_scenarios();
		$scenario = isset( $scenarios[ $scenario_key ] ) ? $scenarios[ $scenario_key ] : array();

		$invoice_data = array(
			'invoice_id'        => 0,
			'order_id'          => $order_id,
			'invoice_number'    => 'TEST-' . time(),
			'tipo_factura'      => isset( $scenario['invoice_type'] ) ? $scenario['invoice_type'] : 'F1',
			'aeat_final_status' => 'pending',
			'subsanation_count' => 0,
			'error_category'    => '',
		);

		// Apply scenario setup overrides
		if ( isset( $scenario['setup'] ) && is_array( $scenario['setup'] ) ) {
			$invoice_data = array_merge( $invoice_data, $scenario['setup'] );
		}

		return $invoice_data;
	}

	/**
	 * Run a test scenario and return the result.
	 *
	 * @param string $scenario_key Scenario key.
	 * @param int    $order_id     Optional order ID (for real database testing).
	 * @return array Test result with expected vs actual comparison.
	 */
	public static function run_scenario( $scenario_key, $order_id = 0 ) {
		$scenarios = self::get_all_scenarios();

		if ( ! isset( $scenarios[ $scenario_key ] ) ) {
			return array(
				'success' => false,
				'error'   => 'Unknown scenario: ' . $scenario_key,
			);
		}

		$scenario = $scenarios[ $scenario_key ];
		$mock_response = self::create_mock_response( $scenario_key );
		$invoice_data = self::create_mock_invoice_data( $scenario_key, $order_id ?: 12345 );

		// Classify the response
		$classified_response = Freefactu_Aeat_Error_Classifier::classify_response( $mock_response );

		// Run the decider
		$decision = Freefactu_Aeat_Next_Action_Decider::decide( $invoice_data, $classified_response );

		// Compare with expected
		$expected = $scenario['expected'];
		$actual = array(
			'status'         => $classified_response->get_status(),
			'error_category' => $classified_response->get_error_category(),
			'next_action'    => $decision['next_action'],
		);

		$passed = true;
		$mismatches = array();

		foreach ( $expected as $key => $expected_value ) {
			if ( isset( $actual[ $key ] ) && $actual[ $key ] !== $expected_value ) {
				$passed = false;
				$mismatches[ $key ] = array(
					'expected' => $expected_value,
					'actual'   => $actual[ $key ],
				);
			}
		}

		return array(
			'success'      => $passed,
			'scenario'     => $scenario['name'],
			'description'  => $scenario['description'],
			'expected'     => $expected,
			'actual'       => $actual,
			'mismatches'   => $mismatches,
			'user_message' => $decision['user_message'],
			'instruction'  => $decision['instruction'],
		);
	}

	/**
	 * Run all test scenarios.
	 *
	 * @return array Results for all scenarios.
	 */
	public static function run_all_scenarios() {
		$scenarios = self::get_all_scenarios();
		$results = array();
		$passed = 0;
		$failed = 0;

		foreach ( array_keys( $scenarios ) as $key ) {
			$result = self::run_scenario( $key );
			$results[ $key ] = $result;

			if ( $result['success'] ) {
				$passed++;
			} else {
				$failed++;
			}
		}

		return array(
			'total'   => count( $scenarios ),
			'passed'  => $passed,
			'failed'  => $failed,
			'results' => $results,
		);
	}

	/**
	 * Render test results as HTML (for admin page).
	 *
	 * @param array $all_results Results from run_all_scenarios().
	 * @return string HTML output.
	 */
	public static function render_results_html( $all_results ) {
		$html = '<div class="aeat-test-results">';
		
		// Summary
		$html .= sprintf(
			'<div class="test-summary %s">
				<strong>%s</strong>: %d/%d %s
			</div>',
			$all_results['failed'] > 0 ? 'has-failures' : 'all-passed',
			__( 'Test Results', 'freefactu' ),
			$all_results['passed'],
			$all_results['total'],
			__( 'tests passed', 'freefactu' )
		);

		// Individual results
		$html .= '<table class="widefat striped">';
		$html .= '<thead><tr><th>' . __( 'Scenario', 'freefactu' ) . '</th><th>' . __( 'Status', 'freefactu' ) . '</th><th>' . __( 'Details', 'freefactu' ) . '</th></tr></thead>';
		$html .= '<tbody>';

		foreach ( $all_results['results'] as $key => $result ) {
			$status_icon = $result['success'] ? '<span class="dashicons dashicons-yes-alt" style="color: #46b450;"></span>' : '<span class="dashicons dashicons-dismiss" style="color: #dc3232;"></span>';
			$status_class = $result['success'] ? 'passed' : 'failed';
			
			$details = '';
			if ( ! $result['success'] && ! empty( $result['mismatches'] ) ) {
				foreach ( $result['mismatches'] as $field => $mismatch ) {
					$details .= sprintf(
						'<div class="mismatch"><code>%s</code>: expected <code>%s</code>, got <code>%s</code></div>',
						esc_html( $field ),
						esc_html( $mismatch['expected'] ),
						esc_html( $mismatch['actual'] )
					);
				}
			} else {
				$details = '<em>' . esc_html( $result['user_message'] ) . '</em>';
			}

			$html .= sprintf(
				'<tr class="%s">
					<td><strong>%s</strong><br><small>%s</small></td>
					<td>%s</td>
					<td>%s</td>
				</tr>',
				esc_attr( $status_class ),
				esc_html( $result['scenario'] ),
				esc_html( $result['description'] ),
				$status_icon,
				$details
			);
		}

		$html .= '</tbody></table>';
		$html .= '</div>';
		// Styles moved to assets/css/freefactu-admin.css

		return $html;
	}
}
