<?php

declare(strict_types=1);

namespace Instinctor\Services;

use Instinctor\Core\Config;
use Instinctor\Core\DB;


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

/**
 * Tax Service
 * Manages tax rates and calculates taxes
 */
class TaxService
{
    public function getRates(): array
    {
        $table = DB::prefix() . 'instinctor_tax_rates';
        return DB::get_results("SELECT * FROM $table ORDER BY country, state, priority, sort_order");
    }

    public function getRate(int $id): ?object
    {
        $table = DB::prefix() . 'instinctor_tax_rates';
        return DB::get_row(DB::prepare("SELECT * FROM $table WHERE id = %d", $id));
    }

    public function createRate(array $data): int
    {
        $table = DB::prefix() . 'instinctor_tax_rates';

        DB::insert($table, [
            'country' => strtoupper(sanitize_text_field($data['country'] ?? '')),
            'state' => sanitize_text_field($data['state'] ?? ''),
            'postcode' => sanitize_text_field($data['postcode'] ?? ''),
            'city' => sanitize_text_field($data['city'] ?? ''),
            'rate' => floatval($data['rate'] ?? 0),
            'name' => sanitize_text_field($data['name'] ?? 'Tax'),
            'priority' => intval($data['priority'] ?? 1),
            'compound' => !empty($data['compound']) ? 1 : 0,
            'shipping' => isset($data['shipping']) ? ($data['shipping'] ? 1 : 0) : 1,
            'sort_order' => intval($data['sort_order'] ?? 0),
        ]);

        return (int) DB::insert_id();
    }

    public function updateRate(int $id, array $data): bool
    {
        $table = DB::prefix() . 'instinctor_tax_rates';

        $update = [];
        if (isset($data['country'])) $update['country'] = strtoupper(sanitize_text_field($data['country']));
        if (isset($data['state'])) $update['state'] = sanitize_text_field($data['state']);
        if (isset($data['postcode'])) $update['postcode'] = sanitize_text_field($data['postcode']);
        if (isset($data['city'])) $update['city'] = sanitize_text_field($data['city']);
        if (isset($data['rate'])) $update['rate'] = floatval($data['rate']);
        if (isset($data['name'])) $update['name'] = sanitize_text_field($data['name']);
        if (isset($data['priority'])) $update['priority'] = intval($data['priority']);
        if (isset($data['compound'])) $update['compound'] = $data['compound'] ? 1 : 0;
        if (isset($data['shipping'])) $update['shipping'] = $data['shipping'] ? 1 : 0;

        return DB::update($table, $update, ['id' => $id]) !== false;
    }

    public function deleteRate(int $id): bool
    {
        return DB::delete(DB::prefix() . 'instinctor_tax_rates', ['id' => $id]) !== false;
    }

    /**
     * Calculate tax for a cart
     */
    public function calculateTax(float $subtotal, array $address, bool $includeShipping = false, float $shippingCost = 0): array
    {
        if (!Config::get('instinctor_tax_enabled', false)) {
            return ['total' => 0, 'rates' => []];
        }

        $matchingRates = $this->getMatchingRates($address);
        
        if (empty($matchingRates)) {
            return ['total' => 0, 'rates' => []];
        }

        $taxes = [];
        $totalTax = 0;
        $taxableAmount = $subtotal;

        // Group rates by priority
        $ratesByPriority = [];
        foreach ($matchingRates as $rate) {
            $ratesByPriority[$rate->priority][] = $rate;
        }
        ksort($ratesByPriority);

        foreach ($ratesByPriority as $priority => $rates) {
            $priorityTax = 0;
            
            foreach ($rates as $rate) {
                $amount = $taxableAmount;
                
                // Add shipping if applicable
                if ($includeShipping && $rate->shipping && $shippingCost > 0) {
                    $amount += $shippingCost;
                }

                $tax = $amount * ($rate->rate / 100);
                $priorityTax += $tax;
                
                $taxes[] = [
                    'name' => $rate->name,
                    'rate' => $rate->rate,
                    'amount' => round($tax, 2),
                ];
            }
            
            $totalTax += $priorityTax;
            
            // For compound taxes, add this priority's tax to the base for next priority
            if (!empty($rates[0]->compound)) {
                $taxableAmount += $priorityTax;
            }
        }

        return [
            'total' => round($totalTax, 2),
            'rates' => $taxes,
        ];
    }

    /**
     * Get tax rates matching an address
     */
    public function getMatchingRates(array $address): array
    {
        $table = DB::prefix() . 'instinctor_tax_rates';

        $country = strtoupper($address['country'] ?? '');
        $state = $address['state'] ?? '';
        $postcode = $address['postcode'] ?? '';
        $city = $address['city'] ?? '';

        if (empty($country)) {
            return [];
        }

        // Get all rates for this country
        $rates = DB::get_results(DB::prepare(
            "SELECT * FROM $table WHERE country = %s ORDER BY priority, sort_order",
            $country
        ));

        $matched = [];
        foreach ($rates as $rate) {
            // Check state match
            if ($rate->state && strtolower($rate->state) !== strtolower($state)) {
                // Check for wildcard
                if ($rate->state !== '*') {
                    continue;
                }
            }

            // Check postcode match (if specified)
            if ($rate->postcode && !$this->matchPostcode($postcode, $rate->postcode)) {
                continue;
            }

            // Check city match (if specified)
            if ($rate->city && strtolower($rate->city) !== strtolower($city)) {
                if ($rate->city !== '*') {
                    continue;
                }
            }

            $matched[] = $rate;
        }

        return $matched;
    }

    private function matchPostcode(string $postcode, string $pattern): bool
    {
        $postcode = strtoupper(preg_replace('/\s+/', '', $postcode));
        $patterns = array_map('trim', explode(';', $pattern));

        foreach ($patterns as $p) {
            $p = strtoupper(preg_replace('/\s+/', '', $p));
            
            // Exact match
            if ($postcode === $p) {
                return true;
            }

            // Wildcard match
            if (strpos($p, '*') !== false) {
                $regex = '/^' . str_replace('*', '.*', preg_quote($p, '/')) . '$/';
                if (preg_match($regex, $postcode)) {
                    return true;
                }
            }

            // Range match
            if (strpos($p, '...') !== false) {
                [$start, $end] = explode('...', $p);
                if ($postcode >= $start && $postcode <= $end) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * Get commonly used tax rate templates
     */
    public static function getTemplates(): array
    {
        return [
            'us_california' => [
                'country' => 'US',
                'state' => 'CA',
                'rate' => 7.25,
                'name' => 'CA State Tax',
            ],
            'us_texas' => [
                'country' => 'US',
                'state' => 'TX',
                'rate' => 6.25,
                'name' => 'TX State Tax',
            ],
            'us_new_york' => [
                'country' => 'US',
                'state' => 'NY',
                'rate' => 4.0,
                'name' => 'NY State Tax',
            ],
            'uk_vat' => [
                'country' => 'GB',
                'state' => '',
                'rate' => 20.0,
                'name' => 'VAT',
            ],
            'eu_vat' => [
                'country' => 'DE',
                'state' => '',
                'rate' => 19.0,
                'name' => 'MwSt',
            ],
            'ca_gst' => [
                'country' => 'CA',
                'state' => '',
                'rate' => 5.0,
                'name' => 'GST',
            ],
        ];
    }
}
