import hashlib
import json
from decimal import Decimal
from enum import Enum
from typing import Any

from common_logging import get_logger

logger = get_logger(__name__)


class TaxpayerType(str, Enum):
    GENERAL = 'general'
    SMALL_SCALE = 'small_scale'

class TaxType(str, Enum):
    VAT = 'vat'
    CORPORATE_INCOME = 'corporate_income'
    PERSONAL_INCOME = 'personal_income'
    STAMP = 'stamp'

class TaxCalculationEngine:

    def __init__(self):
        self._cache = {}
        self._cache_max_size = 1000
        self.vat_rates = {'general_13': Decimal('0.13'), 'general_9': Decimal('0.09'), 'general_6': Decimal('0.06'), 'small_scale_3': Decimal('0.03'), 'small_scale_1': Decimal('0.01')}
        self.corporate_income_rates = {'standard': Decimal('0.25'), 'small_profit': Decimal('0.05'), 'high_tech': Decimal('0.15')}
        self.personal_income_brackets = [(Decimal('36000'), Decimal('0.03')), (Decimal('144000'), Decimal('0.10')), (Decimal('300000'), Decimal('0.20')), (Decimal('420000'), Decimal('0.25')), (Decimal('660000'), Decimal('0.30')), (Decimal('960000'), Decimal('0.35')), (None, Decimal('0.45'))]
        self.stamp_tax_rates = {'purchase_sale': Decimal('0.0003'), 'loan': Decimal('0.00005'), 'property_lease': Decimal('0.001'), 'rights_transfer': Decimal('0.0005')}

    def _get_cache_key(self, method: str, **kwargs) -> str:
        params_str = json.dumps(kwargs, sort_keys=True, default=str)
        key = f'{method}:{hashlib.md5(params_str.encode()).hexdigest()}'
        return key

    def _get_from_cache(self, key: str) -> dict[str, Any] | None:
        return self._cache.get(key)

    def _set_to_cache(self, key: str, value: dict[str, Any]):
        if len(self._cache) >= self._cache_max_size:
            first_key = next(iter(self._cache))
            del self._cache[first_key]
        self._cache[key] = value

    def calculate_vat(self, sales_amount: Decimal, taxpayer_type: TaxpayerType, rate_type: str='general_13', input_tax: Decimal | None=None) -> dict[str, Any]:
        cache_key = self._get_cache_key('vat', sales_amount=str(sales_amount), taxpayer_type=taxpayer_type, rate_type=rate_type, input_tax=str(input_tax) if input_tax else None)
        cached_result = self._get_from_cache(cache_key)
        if cached_result:
            return cached_result
        try:
            rate = self.vat_rates.get(rate_type)
            if not rate:
                raise ValueError(f'Invalid rate type: {rate_type}')
            output_tax = sales_amount * rate
            if taxpayer_type == TaxpayerType.GENERAL and input_tax:
                payable_tax = output_tax - input_tax
            else:
                payable_tax = output_tax
            result = {'tax_type': 'vat', 'sales_amount': float(sales_amount), 'rate': float(rate), 'output_tax': float(output_tax), 'input_tax': float(input_tax) if input_tax else 0, 'payable_tax': float(payable_tax), 'taxpayer_type': taxpayer_type}
            self._set_to_cache(cache_key, result)
            return result
        except Exception as e:
            logger.error(f'VAT calculation failed: {e}')
            raise

    def calculate_corporate_income_tax(self, taxable_income: Decimal, rate_type: str='standard', deductions: Decimal | None=None) -> dict[str, Any]:
        cache_key = self._get_cache_key('corporate_income', taxable_income=str(taxable_income), rate_type=rate_type, deductions=str(deductions) if deductions else None)
        cached_result = self._get_from_cache(cache_key)
        if cached_result:
            return cached_result
        try:
            rate = self.corporate_income_rates.get(rate_type)
            if not rate:
                raise ValueError(f'Invalid rate type: {rate_type}')
            if deductions:
                taxable_income = taxable_income - deductions
            payable_tax = taxable_income * rate
            result = {'tax_type': 'corporate_income', 'taxable_income': float(taxable_income), 'rate': float(rate), 'rate_type': rate_type, 'deductions': float(deductions) if deductions else 0, 'payable_tax': float(payable_tax)}
            self._set_to_cache(cache_key, result)
            return result
        except Exception as e:
            logger.error(f'Corporate income tax calculation failed: {e}')
            raise

    def calculate_personal_income_tax(self, annual_income: Decimal, special_deductions: Decimal | None=None) -> dict[str, Any]:
        cache_key = self._get_cache_key('personal_income', annual_income=str(annual_income), special_deductions=str(special_deductions) if special_deductions else None)
        cached_result = self._get_from_cache(cache_key)
        if cached_result:
            return cached_result
        try:
            basic_deduction = Decimal('60000')
            taxable_income = annual_income - basic_deduction
            if special_deductions:
                taxable_income = taxable_income - special_deductions
            if taxable_income <= 0:
                result = {'tax_type': 'personal_income', 'annual_income': float(annual_income), 'taxable_income': 0, 'payable_tax': 0, 'effective_rate': 0}
                self._set_to_cache(cache_key, result)
                return result
            payable_tax = Decimal('0')
            previous_bracket = Decimal('0')
            for bracket_limit, rate in self.personal_income_brackets:
                if bracket_limit is None:
                    amount_in_bracket = taxable_income - previous_bracket
                    payable_tax += amount_in_bracket * rate
                    break
                elif taxable_income <= bracket_limit:
                    amount_in_bracket = taxable_income - previous_bracket
                    payable_tax += amount_in_bracket * rate
                    break
                else:
                    amount_in_bracket = bracket_limit - previous_bracket
                    payable_tax += amount_in_bracket * rate
                    previous_bracket = bracket_limit
            effective_rate = payable_tax / annual_income if annual_income > 0 else Decimal('0')
            result = {'tax_type': 'personal_income', 'annual_income': float(annual_income), 'basic_deduction': float(basic_deduction), 'special_deductions': float(special_deductions) if special_deductions else 0, 'taxable_income': float(taxable_income), 'payable_tax': float(payable_tax), 'effective_rate': float(effective_rate)}
            self._set_to_cache(cache_key, result)
            return result
        except Exception as e:
            logger.error(f'Personal income tax calculation failed: {e}')
            raise

    def calculate_stamp_tax(self, contract_amount: Decimal, contract_type: str='purchase_sale') -> dict[str, Any]:
        cache_key = self._get_cache_key('stamp', contract_amount=str(contract_amount), contract_type=contract_type)
        cached_result = self._get_from_cache(cache_key)
        if cached_result:
            return cached_result
        try:
            rate = self.stamp_tax_rates.get(contract_type)
            if not rate:
                raise ValueError(f'Invalid contract type: {contract_type}')
            payable_tax = contract_amount * rate
            result = {'tax_type': 'stamp', 'contract_amount': float(contract_amount), 'contract_type': contract_type, 'rate': float(rate), 'payable_tax': float(payable_tax)}
            self._set_to_cache(cache_key, result)
            return result
        except Exception as e:
            logger.error(f'Stamp tax calculation failed: {e}')
            raise

    def apply_tax_incentive(self, calculation_result: dict[str, Any], incentive_type: str, incentive_rate: Decimal | None=None) -> dict[str, Any]:
        try:
            original_tax = Decimal(str(calculation_result['payable_tax']))
            if incentive_type == 'exemption':
                final_tax = Decimal('0')
                incentive_amount = original_tax
            elif incentive_type == 'reduction' and incentive_rate:
                incentive_amount = original_tax * incentive_rate
                final_tax = original_tax - incentive_amount
            elif incentive_type == 'refund' and incentive_rate:
                incentive_amount = original_tax * incentive_rate
                final_tax = original_tax - incentive_amount
            else:
                raise ValueError(f'Invalid incentive type or missing rate: {incentive_type}')
            result = calculation_result.copy()
            result.update({'original_tax': float(original_tax), 'incentive_type': incentive_type, 'incentive_amount': float(incentive_amount), 'final_tax': float(final_tax)})
            return result
        except Exception as e:
            logger.error(f'Tax incentive application failed: {e}')
            raise

    def clear_cache(self):
        self._cache.clear()
        logger.info('Tax calculation cache cleared')

    def get_cache_stats(self) -> dict[str, Any]:
        return {'cache_size': len(self._cache), 'cache_max_size': self._cache_max_size}
_tax_calculation_engine = None

def get_tax_calculation_engine() -> TaxCalculationEngine:
    global _tax_calculation_engine
    if _tax_calculation_engine is None:
        _tax_calculation_engine = TaxCalculationEngine()
    return _tax_calculation_engine
