<?php
/**
 * Tax specific utility class.
 *
 * @package     EDD\Pro\Taxes\VAT
 * @copyright   Copyright (c) 2025, Sandhills Development, LLC
 * @license     https://opensource.org/licenses/gpl-2.0.php GNU Public License
 * @since       3.5.0
 */

namespace EDD\Pro\Taxes\VAT;

// Exit if accessed directly.
defined( 'ABSPATH' ) || exit; // @codeCoverageIgnore

use EDD\Utils\Countries;

/**
 * Utility class.
 *
 * @since 3.5.0
 */
class Utility {

	/**
	 * Checks whether reverse charge is supported in a specific country.
	 *
	 * @param string $country_code The country code to check.
	 * @return mixed
	 */
	public static function can_reverse_charge_vat( $country_code ) {

		$eu_countries = Countries::get_eu_countries();

		/**
		 * If we're applying VAT in the base country (i.e. not reverse charging), remove it from countries list.
		 *
		 * @link https://europa.eu/youreurope/business/taxation/vat/cross-border-vat/index_en.htm#withintheeusellgoodsanotherbusiness
		 */
		if ( ! self::reverse_charge_in_base_country() ) {
			$base_country = self::get_country_for_api();

			/**
			 * If the base country is set to EU, use the EDD shop country instead.
			 */
			if ( 'EU' === $base_country ) {
				$base_country = edd_get_shop_country();
			}

			$eu_countries = array_diff( $eu_countries, array( $base_country ) );
		}

		return apply_filters( 'edd_vat_can_reverse_charge_vat', in_array( $country_code, $eu_countries, true ), $country_code );
	}

	/**
	 * Formats an EDD address array.
	 *
	 * @param array $address The address array to format.
	 * @return string
	 */
	public static function format_edd_address( $address ) {
		$defaults = array(
			'line1'   => '',
			'line2'   => '',
			'city'    => '',
			'state'   => '',
			'zip'     => '',
			'country' => '',
		);

		$address = wp_parse_args( $address, $defaults );

		$address_lines  = array( $address['line1'], $address['line2'] );
		$city_zip_state = array( $address['city'], $address['zip'] );

		if ( $address['country'] && $address['state'] ) {
			$city_zip_state[] = edd_get_state_name( $address['country'], $address['state'] );
		}
		$address_lines[] = implode( ' ', array_filter( $city_zip_state ) );

		if ( $address['country'] ) {
			$address_lines[] = edd_get_country_name( $address['country'] );
		}

		$formatted_address = implode( "\n", array_filter( $address_lines ) );

		return apply_filters( 'edd_vat_address_format', $formatted_address, $address );
	}


	/**
	 * Returns a list of EU countries plus the United Kingdom.
	 *
	 * @return array
	 */
	public static function get_eu_countries_list() {
		return include EDD_PLUGIN_DIR . 'i18n/countries-eu.php';
	}

	/**
	 * Get the list of countries plus our custom ones.
	 *
	 * @since 3.5.0
	 * @param bool $with_moss Whether to include the EU MOSS number.
	 * @return array
	 */
	public static function get_country_list( $with_moss = true ) {

		$countries = self::get_eu_countries_list();

		if ( $with_moss ) {
			$countries = self::array_insert_after( 'GB', $countries, 'EU', __( 'EU MOSS Number', 'easy-digital-downloads' ) );
		}

		return self::array_insert_after( 'IE', $countries, 'XI', __( 'Northern Ireland', 'easy-digital-downloads' ) );
	}

	/**
	 * Return the country to use for the API.
	 *
	 * @since 3.5.0
	 * @return string
	 */
	public static function get_country_for_api() {
		return edd_get_option( 'edd_vat_address_country', edd_get_shop_country() );
	}

	/**
	 * Retrieves an array of EU VAT number prefixes keyed by country code.
	 *
	 * @since 3.5.0
	 * @return string[]
	 */
	public static function get_eu_vat_number_prefixes(): array {
		$eu_countries    = Countries::get_eu_countries();
		$eu_vat_prefixes = array_combine( $eu_countries, $eu_countries );

		// Greek VAT numbers begin with EL, not GR.
		$eu_vat_prefixes['GR'] = 'EL';

		return $eu_vat_prefixes;
	}

	/**
	 * Inserts a new key/value after the key in the array.
	 *
	 * @param string $key            The key to insert after.
	 * @param array  $original_array An array to insert in to.
	 * @param string $new_key        The key to insert.
	 * @param mixed  $new_value      A value to insert.
	 *
	 * @return array The new array, or the original array if the key is not found.
	 */
	public static function array_insert_after( $key, array &$original_array, $new_key, $new_value ) {
		if ( ! array_key_exists( $key, $original_array ) ) {
			return $original_array;
		}

		$position           = array_search( $key, array_keys( $original_array ), true );
		$result             = array_slice( $original_array, 0, $position + 1, true );
		$result[ $new_key ] = $new_value;
		$result            += array_slice( $original_array, $position + 1, null, true ); // Use "+" to preserve keys.

		return $result;
	}

	/**
	 * Whether or not to reverse charge VAT in the base country.
	 *
	 * @since 3.5.0
	 * @return bool
	 */
	private static function reverse_charge_in_base_country(): bool {
		return (bool) edd_get_option( 'edd_vat_reverse_charge_base_country', false );
	}
}
