<?php
/**
 * AEAT Next Action Decider
 *
 * Core decision logic for determining what action to take after an AEAT response.
 * Implements the business rules for subsanation vs rectificativa.
 *
 * @package Freefactu
 * @since 1.1.0
 */

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

/**
 * Class Freefactu_Aeat_Next_Action_Decider
 *
 * Determines the appropriate next action based on:
 * - AEAT response status and error category
 * - Invoice type (F1, F2, F3, F4)
 * - Current invoice state (accepted, rejected, subsanated)
 * - Number of previous subsanation attempts
 *
 * KEY BUSINESS RULES:
 * 1. Subsanation fixes the MESSAGE, not the CONTENT
 * 2. F2 (cancellation) CANNOT be subsanated - must send new F2
 * 3. Already-accepted invoices CANNOT be subsanated - must use rectificativa
 * 4. Business/content errors require rectificativa, NEVER subsanation
 */
class Freefactu_Aeat_Next_Action_Decider {

	/**
	 * Default maximum subsanation attempts.
	 *
	 * @var int
	 */
	const DEFAULT_MAX_SUBSANATION_ATTEMPTS = 3;

	/**
	 * Invoice types that CAN be subsanated.
	 *
	 * @var array
	 */
	private static $subsanable_invoice_types = array( 'F1', 'F3', 'F4', 'R1', 'R2', 'R3', 'R4', 'R5' );

	/**
	 * Decide the next action for an invoice based on AEAT response.
	 *
	 * @param array         $invoice_data Invoice context data.
	 * @param Freefactu_Aeat_Response $response     Classified AEAT response.
	 * @return array Decision result with keys: next_action, user_message, can_auto_retry.
	 */
	public static function decide( array $invoice_data, Freefactu_Aeat_Response $response ) {
		// Extract invoice context
		$invoice_id       = isset( $invoice_data['invoice_id'] ) ? $invoice_data['invoice_id'] : 0;
		$tipo_factura     = isset( $invoice_data['tipo_factura'] ) ? strtoupper( $invoice_data['tipo_factura'] ) : 'F1';
		$current_status   = isset( $invoice_data['aeat_final_status'] ) ? $invoice_data['aeat_final_status'] : 'pending';
		$subsanation_count= isset( $invoice_data['subsanation_count'] ) ? (int) $invoice_data['subsanation_count'] : 0;

		// Get max attempts (filterable)
		$max_attempts = apply_filters(
			'freefactu_max_subsanation_attempts',
			self::DEFAULT_MAX_SUBSANATION_ATTEMPTS,
			$invoice_data
		);

		// ===== DECISION TREE =====

		// 1. If response is SUCCESS → NO_ACTION_NEEDED
		if ( $response->is_success() ) {
			return self::build_result(
				Freefactu_Aeat_Next_Action::NO_ACTION_NEEDED,
				__( 'La factura ha sido aceptada correctamente por la AEAT.', 'freefactu' ),
				false
			);
		}

		// 2. If invoice was ALREADY ACCEPTED → must use rectificativa
		// You cannot "fix" an accepted invoice with subsanation
		if ( $current_status === 'accepted' ) {
			return self::build_result(
				Freefactu_Aeat_Next_Action::CREATE_RECTIFICATIVA,
				__( 'Esta factura ya fue aceptada por la AEAT. Para corregir su contenido, debe crear una factura rectificativa (F3).', 'freefactu' ),
				false
			);
		}

		// 3. If invoice type is F2 (cancellation) → cannot subsanar, must retry with new F2
		if ( $tipo_factura === 'F2' ) {
			return self::build_result(
				Freefactu_Aeat_Next_Action::RETRY_NEW_F2,
				sprintf(
					/* translators: %s: Error description */
					__( 'La anulación ha sido rechazada: %s. Debe enviar una nueva solicitud de anulación.', 'freefactu' ),
					$response->get_error_description()
				),
				true
			);
		}

		$error_category = $response->get_error_category();

		// 4. If error is CLIENT category → unlimited retry (not subsanation)
		// These are library validation errors before AEAT was called
		if ( $error_category === Freefactu_Aeat_Error_Categories::CLIENT ) {
			// Humanize the raw error message to make it user-friendly
			$human_error = class_exists( 'Freefactu_Client_Error_Helper' )
				? Freefactu_Client_Error_Helper::humanize( $response->get_error_description() )
				: $response->get_error_description();
			
			return self::build_result(
				Freefactu_Aeat_Next_Action::RETRY_CLIENT,
				sprintf(
					/* translators: %s: Human readable error message */
					__( '%s Corrija el problema y pulse "Reintentar".', 'freefactu' ),
					$human_error
				),
				true
			);
		}

		// 5. If error is BUSINESS category → cannot subsanar (content error)
		if ( $error_category === Freefactu_Aeat_Error_Categories::BUSINESS ) {
			return self::build_result(
				Freefactu_Aeat_Next_Action::CREATE_RECTIFICATIVA,
				sprintf(
					/* translators: %s: Error description */
					__( 'Error de contenido económico: %s. Este tipo de error no puede subsanarse. Debe crear una factura rectificativa para corregir los importes o datos fiscales.', 'freefactu' ),
					$response->get_error_description()
				),
				false
			);
		}

		// 5. If error is NETWORK → retry (not subsanation)
		if ( $error_category === Freefactu_Aeat_Error_Categories::NETWORK ) {
			return self::build_result(
				Freefactu_Aeat_Next_Action::RETRY_SUBSANATION, // Actually just retry, same data
				sprintf(
					/* translators: %s: Error description */
					__( 'Error de conexión: %s. Puede reintentar el envío.', 'freefactu' ),
					$response->get_error_description()
				),
				true
			);
		}

		// 6. If max subsanation attempts reached → manual intervention
		if ( $subsanation_count >= $max_attempts ) {
			return self::build_result(
				Freefactu_Aeat_Next_Action::MANUAL_INTERVENTION,
				sprintf(
					/* translators: 1: Max attempts, 2: Error description */
					__( 'Se ha alcanzado el máximo de %1$d intentos de subsanación. Error: %2$s. Se requiere intervención manual para resolver este problema.', 'freefactu' ),
					$max_attempts,
					$response->get_error_description()
				),
				false
			);
		}

		// 7. If invoice type is subsanable AND error category is subsanable → CAN SUBSANAR
		$is_subsanable_type = in_array( $tipo_factura, self::$subsanable_invoice_types, true );
		$is_subsanable_category = Freefactu_Aeat_Error_Categories::is_subsanable_category( $error_category );

		if ( $is_subsanable_type && $is_subsanable_category ) {
			$attempts_left = $max_attempts - $subsanation_count;
			
			return self::build_result(
				Freefactu_Aeat_Next_Action::RETRY_SUBSANATION,
				sprintf(
					/* translators: 1: Error category label, 2: Error description, 3: Attempts left */
					__( '%1$s: %2$s. Corrija el problema y pulse "Subsanar" para reenviar. (%3$d intentos restantes)', 'freefactu' ),
					Freefactu_Aeat_Error_Categories::get_label( $error_category ),
					$response->get_error_description(),
					$attempts_left
				),
				true
			);
		}

		// 8. If error is UNKNOWN → manual intervention
		if ( $error_category === Freefactu_Aeat_Error_Categories::UNKNOWN ) {
			return self::build_result(
				Freefactu_Aeat_Next_Action::MANUAL_INTERVENTION,
				sprintf(
					/* translators: %s: Error description */
					__( 'Error no clasificado: %s. Se requiere revisión manual para determinar la acción correcta.', 'freefactu' ),
					$response->get_error_description()
				),
				false
			);
		}

		// 9. Default: FATAL ERROR
		return self::build_result(
			Freefactu_Aeat_Next_Action::SHOW_FATAL_ERROR,
				sprintf(
					/* translators: %s: Error description */
					__( 'Error irrecuperable: %s. No se puede procesar automáticamente esta factura.', 'freefactu' ),
					$response->get_error_description()
				),
			false
		);
	}

	/**
	 * Build a standardized result array.
	 *
	 * @param string $next_action   One of Freefactu_Aeat_Next_Action constants.
	 * @param string $user_message  Spanish message for the user.
	 * @param bool   $can_auto_retry Whether automatic retry is possible.
	 * @return array
	 */
	private static function build_result( $next_action, $user_message, $can_auto_retry ) {
		// Allow external override of the decision
		$filtered_action = apply_filters(
			'freefactu_next_action_override',
			$next_action,
			$user_message,
			$can_auto_retry
		);

		return array(
			'next_action'    => $filtered_action,
			'user_message'   => $user_message,
			'can_auto_retry' => $can_auto_retry,
			'action_label'   => Freefactu_Aeat_Next_Action::get_label( $filtered_action ),
			'instruction'    => Freefactu_Aeat_Next_Action::get_instruction( $filtered_action ),
		);
	}

	/**
	 * Check if an invoice can be subsanated.
	 * Utility method for quick checks.
	 *
	 * @param string $tipo_factura   Invoice type (F1, F2, F3, F4, R1-R5).
	 * @param string $current_status Current AEAT status.
	 * @param string $error_category Error category.
	 * @return bool
	 */
	public static function can_subsanar( $tipo_factura, $current_status, $error_category ) {
		// Cannot subsanar F2 (cancellation)
		if ( strtoupper( $tipo_factura ) === 'F2' ) {
			return false;
		}

		// Cannot subsanar already-accepted invoices
		if ( $current_status === 'accepted' ) {
			return false;
		}

		// Check if invoice type is subsanable
		if ( ! in_array( strtoupper( $tipo_factura ), self::$subsanable_invoice_types, true ) ) {
			return false;
		}

		// Check if error category is subsanable
		if ( ! Freefactu_Aeat_Error_Categories::is_subsanable_category( $error_category ) ) {
			return false;
		}

		return true;
	}

	/**
	 * Explain why subsanation is not possible (for UI).
	 *
	 * @param string $tipo_factura   Invoice type.
	 * @param string $current_status Current AEAT status.
	 * @param string $error_category Error category.
	 * @return string|null Explanation or null if subsanation IS possible.
	 */
	public static function explain_no_subsanation( $tipo_factura, $current_status, $error_category ) {
		$tipo_factura = strtoupper( $tipo_factura );

		if ( $tipo_factura === 'F2' ) {
			return __( 'Las facturas de anulación (F2) no pueden subsanarse. Debe enviar una nueva anulación.', 'freefactu' );
		}

		if ( $current_status === 'accepted' ) {
			return __( 'Esta factura ya fue aceptada por la AEAT. Use una factura rectificativa para correcciones.', 'freefactu' );
		}

		if ( ! in_array( $tipo_factura, self::$subsanable_invoice_types, true ) ) {
			return sprintf(
				/* translators: %s: Invoice type */
				__( 'El tipo de factura %s no permite subsanación.', 'freefactu' ),
				$tipo_factura
			);
		}

		if ( $error_category === Freefactu_Aeat_Error_Categories::BUSINESS ) {
			return __( 'Los errores de contenido económico no pueden subsanarse. La subsanación solo corrige errores de transmisión, no de contenido. Use una factura rectificativa.', 'freefactu' );
		}

		if ( ! Freefactu_Aeat_Error_Categories::is_subsanable_category( $error_category ) ) {
			return sprintf(
				/* translators: %s: Error category label */
				__( 'La categoría de error "%s" no permite subsanación automática.', 'freefactu' ),
				Freefactu_Aeat_Error_Categories::get_label( $error_category )
			);
		}

		return null; // Subsanation IS possible
	}
}
