<?php
/**
 * AEAT Error Categories
 *
 * Enum-like class defining error categories for AEAT VeriFactu responses.
 * Each category represents a class of errors with similar handling requirements.
 *
 * @package Freefactu
 * @since 1.1.0
 */

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

/**
 * Class Freefactu_Aeat_Error_Categories
 *
 * Defines the possible error categories returned by AEAT.
 * Used for classifying errors and determining appropriate next actions.
 *
 * Categories:
 * - CENSUS: NIF/identification errors - typically subsanable
 * - XML_FORMAT: XML/XSD validation errors - typically subsanable
 * - HASH_CHAIN: Hash/chaining errors - may require chain repair
 * - RECTIFICATIVA: R1-R5 specific errors - need logic review
 * - TIMING: Out-of-time submission errors - may need F4
 * - BUSINESS: Business logic errors - require rectificativa, NOT subsanation
 * - NETWORK: Network/connection errors - retry required
 * - UNKNOWN: Unclassified errors - manual intervention needed
 */
class Freefactu_Aeat_Error_Categories {

	/**
	 * Census/identification errors.
	 * Examples: NIF not found, invalid NIF format, NIF not in census.
	 * Typically subsanable: fix NIF data and resend.
	 */
	const CENSUS = 'census';

	/**
	 * XML/XSD format errors.
	 * Examples: XML malformed, XSD validation failed, missing required fields.
	 * Typically subsanable: fix XML structure and resend.
	 */
	const XML_FORMAT = 'xml_format';

	/**
	 * Hash/chaining errors.
	 * Examples: Hash mismatch, previous hash not found, duplicate invoice number.
	 * May require chain initialization or manual intervention.
	 */
	const HASH_CHAIN = 'hash_chain';

	/**
	 * Rectificativa-specific errors.
	 * Examples: Invalid TipoRectificativa, missing original reference.
	 * Typically subsanable: fix rectificativa logic and resend.
	 */
	const RECTIFICATIVA = 'rectificativa';

	/**
	 * Timing/out-of-time errors.
	 * Examples: Invoice sent after legal deadline.
	 * May require F4 (fuera de plazo) submission.
	 */
	const TIMING = 'timing';

	/**
	 * Business logic errors.
	 * Examples: Wrong VAT type, incorrect amounts, wrong customer.
	 * NEVER subsanable - require rectificativa (F3) or new invoice.
	 *
	 * KEY RULE: Subsanation fixes the MESSAGE to AEAT, not the ECONOMIC CONTENT.
	 * Business errors are about content, not transmission.
	 */
	const BUSINESS = 'business';

	/**
	 * Network/connection errors.
	 * Examples: Timeout, connection refused, SSL error.
	 * Should be retried automatically.
	 */
	const NETWORK = 'network';

	/**
	 * Client/library validation errors.
	 * Errors from josemmo/verifactu-php before AEAT API call.
	 * Unlimited retries, no snapshot save/load.
	 * NOT subsanable - just retry after fixing the issue.
	 */
	const CLIENT = 'client';

	/**
	 * Unknown/unclassified errors.
	 * When error cannot be categorized automatically.
	 * Requires manual intervention.
	 */
	const UNKNOWN = 'unknown';

	/**
	 * Get all category constants.
	 *
	 * @return array List of all category constants.
	 */
	public static function get_all() {
		return array(
			self::CENSUS,
			self::XML_FORMAT,
			self::HASH_CHAIN,
			self::RECTIFICATIVA,
			self::TIMING,
			self::BUSINESS,
			self::NETWORK,
			self::CLIENT,
			self::UNKNOWN,
		);
	}

	/**
	 * Get human-readable label for a category (Spanish).
	 *
	 * @param string $category The category constant.
	 * @return string Human-readable label in Spanish.
	 */
	public static function get_label( $category ) {
		$labels = array(
			self::CENSUS        => __( 'Error de censo/identificación', 'freefactu' ),
			self::XML_FORMAT    => __( 'Error de formato XML', 'freefactu' ),
			self::HASH_CHAIN    => __( 'Error de encadenamiento/hash', 'freefactu' ),
			self::RECTIFICATIVA => __( 'Error de rectificativa', 'freefactu' ),
			self::TIMING        => __( 'Error de plazo de presentación', 'freefactu' ),
			self::BUSINESS      => __( 'Error de contenido económico', 'freefactu' ),
			self::NETWORK       => __( 'Error de conexión', 'freefactu' ),
			self::CLIENT        => __( 'Error de validación local', 'freefactu' ),
			self::UNKNOWN       => __( 'Error no clasificado', 'freefactu' ),
		);

		return isset( $labels[ $category ] ) ? $labels[ $category ] : $labels[ self::UNKNOWN ];
	}

	/**
	 * Check if a category is subsanable.
	 *
	 * Categories that CAN be subsanated (message errors, not content errors):
	 * - CENSUS: Fix NIF and resend
	 * - XML_FORMAT: Fix XML structure and resend
	 * - HASH_CHAIN: Fix chain data and resend (with caution)
	 * - RECTIFICATIVA: Fix rectificativa logic and resend
	 *
	 * Categories that CANNOT be subsanated (content errors):
	 * - BUSINESS: Must use rectificativa (F3)
	 * - TIMING: May need F4 or other handling
	 * - NETWORK: Retry, not subsanation
	 * - UNKNOWN: Manual intervention
	 *
	 * @param string $category The category constant.
	 * @return bool True if category is subsanable.
	 */
	public static function is_subsanable_category( $category ) {
		$subsanable = array(
			self::CENSUS,
			self::XML_FORMAT,
			self::HASH_CHAIN,
			self::RECTIFICATIVA,
		);

		return in_array( $category, $subsanable, true );
	}

	/**
	 * Check if a category requires manual intervention.
	 *
	 * @param string $category The category constant.
	 * @return bool True if manual intervention is required.
	 */
	public static function requires_manual_intervention( $category ) {
		return in_array( $category, array( self::UNKNOWN, self::BUSINESS ), true );
	}

	/**
	 * Check if a category is a client-side (library) error.
	 * These errors occur before AEAT API call and allow unlimited retries.
	 *
	 * @param string $category The category constant.
	 * @return bool True if category is a client-side error.
	 */
	public static function is_client_error( $category ) {
		return $category === self::CLIENT;
	}
}
