<?php
/**
 * FajaedeSEO VAT Calculator
 * Handles VAT calculation per EU/non-EU countries for Belgian company
 *
 * @package FajaedeSEO
 */

defined('ABSPATH') || exit;

if (!class_exists('FajaedeSEO_VAT_Calculator')) {

    class FajaedeSEO_VAT_Calculator {

        /**
         * Company details (Belgian)
         */
        const COMPANY_COUNTRY = 'BE';
        const COMPANY_VAT_NUMBER = ''; // Set in admin settings
        const COMPANY_VAT_RATE = 0.21; // Belgium standard VAT
        const OSS_THRESHOLD = 10000.00; // €10,000 threshold for OSS registration (EU)

        /**
         * EU Member States with their standard VAT rates
         * Source: European Commission VAT rates
         */
        private static array $eu_vat_rates = [
            'AT' => 0.20, // Austria
            'BE' => 0.21, // Belgium
            'BG' => 0.20, // Bulgaria
            'HR' => 0.25, // Croatia
            'CY' => 0.19, // Cyprus
            'CZ' => 0.21, // Czech Republic
            'DK' => 0.25, // Denmark
            'EE' => 0.20, // Estonia
            'FI' => 0.24, // Finland
            'FR' => 0.20, // France
            'DE' => 0.19, // Germany
            'GR' => 0.24, // Greece
            'HU' => 0.27, // Hungary
            'IE' => 0.23, // Ireland
            'IT' => 0.22, // Italy
            'LV' => 0.21, // Latvia
            'LT' => 0.21, // Lithuania
            'LU' => 0.17, // Luxembourg
            'MT' => 0.18, // Malta
            'NL' => 0.21, // Netherlands
            'PL' => 0.23, // Poland
            'PT' => 0.23, // Portugal
            'RO' => 0.19, // Romania
            'SK' => 0.20, // Slovakia
            'SI' => 0.22, // Slovenia
            'ES' => 0.21, // Spain
            'SE' => 0.25, // Sweden
        ];

        /**
         * Non-EU countries (0% VAT - Export)
         * Add more as needed
         */
        private static array $non_eu_countries = [
            'US', 'GB', 'UK', 'CA', 'AU', 'JP', 'CN', 'IN',
            'BR', 'MX', 'ZA', 'NZ', 'SG', 'HK', 'AE', 'SA',
            'KR', 'TH', 'MY', 'ID', 'PH', 'VN', 'TR', 'RU',
            'CH', 'NO', 'IS', 'IL', 'EG', 'NG', 'KE', 'MA',
            'TN', 'PK', 'BD', 'LK', 'TW', 'VE', 'AR', 'CL',
            'CO', 'PE', 'UA', 'BY', 'KZ', 'UZ'
        ];

        /**
         * Get VAT rate for a specific country
         *
         * Takes into account:
         * - B2B reverse charge (0% for EU businesses with VAT ID)
         * - Non-EU export (0%)
         * - OSS threshold (€10k/year for simplified regime)
         * - Per-country rates
         *
         * @param string $country_code 2-letter country code
         * @param bool $is_b2b_with_vat_id Whether customer is B2B with valid VAT ID
         * @return float VAT rate (e.g., 0.21 for 21%)
         */
        public static function get_vat_rate($country_code, $is_b2b_with_vat_id = false) {
            $country_code = strtoupper($country_code);

            // B2B within EU with valid VAT number: Reverse charge (0%)
            if ($is_b2b_with_vat_id && self::is_eu_country($country_code)) {
                return 0.0;
            }

            // Non-EU country: 0% (Export)
            if (in_array($country_code, self::$non_eu_countries, true)) {
                return 0.0;
            }

            // EU country: Check OSS threshold (€10k/year)
            if (self::is_eu_country($country_code)) {
                $settings = self::get_settings();
                $voluntary_oss = !empty($settings['voluntary_oss']);

                // If under €10k/year EU B2C turnover and no voluntary OSS: simplified regime (apply home country VAT - Belgium 21%)
                if (!$voluntary_oss && !self::check_oss_threshold_exceeded()) {
                    return self::COMPANY_VAT_RATE;
                }
                // Over €10k or voluntary OSS: apply customer's country VAT (OSS registration required)
                return self::$eu_vat_rates[$country_code];
            }

            // Fallback to Belgian VAT if country not recognized
            return self::COMPANY_VAT_RATE;
        }

        /**
         * Check if annual EU turnover exceeds €10k threshold (for OSS registration)
         *
         * Calculates turnover for current calendar year (Jan 1 - Dec 31)
         * Only counts payments from EU countries (excluding Belgium) for B2C sales
         * Simplified regime applies if under €10k
         *
         * @return bool True if threshold exceeded (OSS registration required), false if under threshold
         */
        public static function check_oss_threshold_exceeded() {
            global $wpdb;
            $table = $wpdb->prefix . 'fajaedeseo_licenses';
            
            $year_start = gmdate('Y-01-01 00:00:00', strtotime('January 1'));
            $year_end = gmdate('Y-12-31 23:59:59', strtotime('December 31'));
            
            // Cache for 1 hour to avoid constant DB queries
            $cache_key = 'fajaedeseo_oss_threshold_' . gmdate('Y');
            $cached = wp_cache_get($cache_key, 'fajaedeseo');
            if (false !== $cached) {
                return $cached;
            }

            $eu_turnover = self::get_year_eu_turnover();
            $threshold_exceeded = $eu_turnover >= self::OSS_THRESHOLD;

            // Cache result for 1 hour
            wp_cache_set($cache_key, $threshold_exceeded, 'fajaedeseo', HOUR_IN_SECONDS);

            return $threshold_exceeded;
        }

        /**
         * Get current year EU B2C turnover (excluding Belgium)
         * Useful for admin settings to show compliance status
         *
         * @return float Annual EU B2C turnover in EUR
         */
        public static function get_year_eu_turnover() {
            global $wpdb;
            $table = $wpdb->prefix . 'fajaedeseo_licenses';
            
            $year_start = gmdate('Y-01-01 00:00:00', strtotime('January 1'));
            $year_end = gmdate('Y-12-31 23:59:59', strtotime('December 31'));
            
            // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
            $result = $wpdb->get_var($wpdb->prepare("
                SELECT COALESCE(SUM(amount), 0) FROM `" . esc_sql($table) . "`
                WHERE payment_id IS NOT NULL 
                AND created_at >= %s 
                AND created_at <= %s
                AND country_code != 'BE'
                AND (customer_type = 'particulier' OR customer_type IS NULL OR customer_type = '')
                AND country_code IN (" . implode(',', array_fill(0, count(array_keys(self::$eu_vat_rates)), '%s')) . ")
            ", array_merge([$year_start, $year_end], array_keys(self::$eu_vat_rates))));

            return (float) $result;
        }

        /**
         * Check if a country is EU member
         *
         * @param string $country_code 2-letter country code
         * @return bool
         */
        public static function is_eu_country($country_code) {
            $country_code = strtoupper($country_code);
            return isset(self::$eu_vat_rates[$country_code]);
        }

        /**
         * Calculate VAT for an order
         *
         * @param float $price_excl_vat Base price without VAT
         * @param string $country_code Customer country code
         * @param bool $is_b2b_with_vat_id Is B2B with valid VAT ID
         * @return array {
         *     'price_excl_vat' => float,
         *     'vat_rate' => float,
         *     'vat_amount' => float,
         *     'price_incl_vat' => float,
         *     'country_code' => string,
         *     'is_reverse_charge' => bool,
         *     'is_export' => bool
         * }
         */
        public static function calculate($price_excl_vat, $country_code, $is_b2b_with_vat_id = false) {
            $vat_rate = self::get_vat_rate($country_code, $is_b2b_with_vat_id);
            $vat_amount = $price_excl_vat * $vat_rate;
            $price_incl_vat = $price_excl_vat + $vat_amount;

            // Determine if this is reverse charge or export
            $is_reverse_charge = $is_b2b_with_vat_id && self::is_eu_country($country_code) && $vat_rate === 0.0;
            $is_export = in_array(strtoupper($country_code), self::$non_eu_countries, true);

            return [
                'price_excl_vat' => round($price_excl_vat, 2),
                'vat_rate' => $vat_rate,
                'vat_amount' => round($vat_amount, 2),
                'price_incl_vat' => round($price_incl_vat, 2),
                'country_code' => strtoupper($country_code),
                'is_reverse_charge' => $is_reverse_charge,
                'is_export' => $is_export
            ];
        }

        /**
         * Get all EU VAT rates (for admin settings)
         *
         * @return array
         */
        public static function get_eu_vat_rates() {
            return self::$eu_vat_rates;
        }

        /**
         * Validate a Belgian VAT number format
         *
         * @param string $vat_number
         * @return bool
         */
        public static function validate_belgian_vat_number($vat_number) {
            // Belgian VAT format: BE0123456789 or 0123456789
            $vat_number = str_replace(['BE', ' ', '-', '.'], '', strtoupper($vat_number));
            return (bool) preg_match('/^\d{10}$/', $vat_number);
        }

        /**
         * Validate a VAT number from any EU country
         *
         * @param string $vat_number Full VAT number (e.g., DE123456789)
         * @return bool
         */
        public static function validate_eu_vat_number($vat_number) {
            // Remove spaces and hyphens
            $vat_number = str_replace([' ', '-', '.'], '', strtoupper($vat_number));

            // Must start with 2-letter country code
            if (strlen($vat_number) < 3) {
                return false;
            }

            $country_code = substr($vat_number, 0, 2);
            $number_part = substr($vat_number, 2);

            // Griekenland gebruikt 'EL' als BTW-prefix, maar de ISO landcode is 'GR'
            $check_country = $country_code;
            if ($check_country === 'EL') {
                $check_country = 'GR';
            }

            // Check if country is EU
            if (!self::is_eu_country($check_country)) {
                return false;
            }

            // Basic length validation (varies by country, but typically 8-12 digits)
            $is_valid_format = (bool) preg_match('/^[0-9A-Z]{8,12}$/', $number_part);
            if (!$is_valid_format) {
                return false;
            }

            // VIES REST API Validatie
            $url = "https://ec.europa.eu/taxation_customs/vies/rest-api/ms/{$country_code}/vat/{$number_part}";
            
            // Gebruik 5 seconden timeout om checkout niet te blokkeren bij trage overheidsservers
            $response = wp_remote_get($url, ['timeout' => 5]);

            if (!is_wp_error($response) && wp_remote_retrieve_response_code($response) === 200) {
                $body = wp_remote_retrieve_body($response);
                $data = json_decode($body, true);
                if (isset($data['isValid'])) {
                    return (bool) $data['isValid'];
                }
            }

            // Fallback naar TRUE als de VIES API onbereikbaar is (om echte B2B verkopen niet te hinderen)
            return true;
        }

        /**
         * Get VAT rate description for invoice
         *
         * @param float $vat_rate VAT rate (0.21, 0.19, etc.)
         * @param string $country_code Customer country code
         * @param bool $is_reverse_charge
         * @param bool $is_export
         * @return string Description for invoice
         */
        public static function get_vat_description($vat_rate, $country_code, $is_reverse_charge = false, $is_export = false) {
            if ($is_reverse_charge) {
                return 'VAT Reverse Charge (Art. 199a VAT Directive)';
            }

            if ($is_export) {
                return 'VAT 0% - Export outside EU';
            }

            if ($vat_rate === 0.0) {
                return 'VAT 0%';
            }

            $percentage = (int) ($vat_rate * 100);
            $country_name = self::get_country_name($country_code);

            return "VAT {$percentage}% ({$country_name})";
        }

        /**
         * Get country name from country code
         *
         * @param string $country_code 2-letter country code
         * @return string Country name
         */
        public static function get_country_name($country_code) {
            $country_code = strtoupper($country_code);

            $countries = [
                'AT' => 'Austria',
                'BE' => 'Belgium',
                'BG' => 'Bulgaria',
                'HR' => 'Croatia',
                'CY' => 'Cyprus',
                'CZ' => 'Czech Republic',
                'DK' => 'Denmark',
                'EE' => 'Estonia',
                'FI' => 'Finland',
                'FR' => 'France',
                'DE' => 'Germany',
                'GR' => 'Greece',
                'HU' => 'Hungary',
                'IE' => 'Ireland',
                'IT' => 'Italy',
                'LV' => 'Latvia',
                'LT' => 'Lithuania',
                'LU' => 'Luxembourg',
                'MT' => 'Malta',
                'NL' => 'Netherlands',
                'PL' => 'Poland',
                'PT' => 'Portugal',
                'RO' => 'Romania',
                'SK' => 'Slovakia',
                'SI' => 'Slovenia',
                'ES' => 'Spain',
                'SE' => 'Sweden',
                'US' => 'United States',
                'GB' => 'United Kingdom',
                'UK' => 'United Kingdom',
                'CA' => 'Canada',
                'AU' => 'Australia',
                'JP' => 'Japan',
                'CN' => 'China',
                'IN' => 'India',
                'BR' => 'Brazil',
                'MX' => 'Mexico',
                'ZA' => 'South Africa',
                'NZ' => 'New Zealand',
            ];

            return $countries[$country_code] ?? $country_code;
        }

        /**
         * Get settings from options (Belgian VAT number)
         *
         * @return array
         */
        public static function get_settings() {
            return [
                'company_vat_number' => get_option('fajaedeseo_company_vat_number', ''),
                'enable_vat_calculation' => get_option('fajaedeseo_enable_vat_calculation', '1'),
                'vat_threshold_eu' => floatval(get_option('fajaedeseo_vat_threshold_eu', 10000)), // €10k threshold
                'voluntary_oss' => get_option('fajaedeseo_voluntary_oss', '0'),
            ];
        }

        /**
         * Format price for display (€ symbol, proper decimals)
         *
         * @param float $amount
         * @return string
         */
        public static function format_price($amount) {
            return '€ ' . number_format($amount, 2, ',', '.');
        }
    }
}
