import json
import copy
import re
from typing import Dict, Any, Optional

from flask import session

from common.extensions import cache_manager
from common.utils.business_event import BusinessEvent
from common.utils.business_event_context import current_event

class TranslationServices:

    @staticmethod
    def translate_config(tenant_id: int, config_data: Dict[str, Any], field_config: str, target_language: str,
                         source_language: Optional[str] = None, context: Optional[str] = None) -> Dict[str, Any]:
        """
        Vertaalt een configuratie op basis van een veld-configuratie.

        Args:
            tenant_id: Identificatie van de tenant waarvoor we de vertaling doen.
            config_data: Een dictionary of JSON (die dan wordt geconverteerd naar een dictionary) met configuratiegegevens
            field_config: De naam van een veld-configuratie (bijv. 'fields')
            target_language: De taal waarnaar vertaald moet worden
            source_language: Optioneel, de brontaal van de configuratie
            context: Optioneel, een specifieke context voor de vertaling

        Returns:
            Een dictionary met de vertaalde configuratie
        """
        config_type = config_data.get('type', 'Unknown')
        config_version = config_data.get('version', 'Unknown')
        span_name = f"{config_type}-{config_version}-{field_config}"

        if current_event:
            with current_event.create_span(span_name):
                translated_config = TranslationServices._translate_config(tenant_id, config_data, field_config,
                                                                          target_language, source_language, context)
                return translated_config
        else:
            with BusinessEvent('Config Translation Service', tenant_id):
                with current_event.create_span(span_name):
                    translated_config = TranslationServices._translate_config(tenant_id, config_data, field_config,
                                                                              target_language, source_language, context)
                    return translated_config

    @staticmethod
    def _translate_config(tenant_id: int, config_data: Dict[str, Any], field_config: str, target_language: str,
                          source_language: Optional[str] = None, context: Optional[str] = None) -> Dict[str, Any]:

        # Zorg ervoor dat we een dictionary hebben
        if isinstance(config_data, str):
            config_data = json.loads(config_data)

        # Maak een deep copy van de originele data om te wijzigen en input-mutatie te vermijden
        translated_config = copy.deepcopy(config_data)

        # Haal type en versie op voor de Business Event span
        config_type = config_data.get('type', 'Unknown')
        config_version = config_data.get('version', 'Unknown')

        if field_config in config_data:
            fields = config_data[field_config]

            # Haal description uit metadata voor context als geen context is opgegeven
            description_context = ""
            if not context and 'metadata' in config_data and 'description' in config_data['metadata']:
                description_context = config_data['metadata']['description']

            # Hulpfuncties
            def is_nonempty_str(val: Any) -> bool:
                return isinstance(val, str) and val.strip() != ''

            def safe_translate(text: str, ctx: Optional[str]):
                try:
                    res = cache_manager.translation_cache.get_translation(
                        text=text,
                        target_lang=target_language,
                        source_lang=source_language,
                        context=ctx
                    )
                    return res.translated_text if res else None
                except Exception as e:
                    if current_event:
                        current_event.log_error('translation_error', {
                            'tenant_id': tenant_id,
                            'config_type': config_type,
                            'config_version': config_version,
                            'field_config': field_config,
                            'error': str(e)
                        })
                    return None

            tag_pair_pattern = re.compile(r'<([a-zA-Z][\w-]*)>[\s\S]*?<\/\1>')

            def extract_tag_counts(text: str) -> Dict[str, int]:
                counts: Dict[str, int] = {}
                for m in tag_pair_pattern.finditer(text or ''):
                    tag = m.group(1)
                    counts[tag] = counts.get(tag, 0) + 1
                return counts

            def tags_valid(source: str, translated: str) -> bool:
                return extract_tag_counts(source) == extract_tag_counts(translated)

            # Counters
            meta_consentRich_translated_count = 0
            meta_aria_translated_count = 0
            meta_inline_tags_invalid_after_translation_count = 0

            # Loop door elk veld in de configuratie
            for field_name, field_data in fields.items():
                # Vertaal name als het bestaat en niet leeg is (alleen strings)
                if 'name' in field_data and is_nonempty_str(field_data['name']):
                    field_context = context if context else description_context
                    t = safe_translate(field_data['name'], field_context)
                    if t:
                        translated_config[field_config][field_name]['name'] = t

                if 'title' in field_data and is_nonempty_str(field_data.get('title')):
                    field_context = context if context else description_context
                    t = safe_translate(field_data['title'], field_context)
                    if t:
                        translated_config[field_config][field_name]['title'] = t

                # Vertaal description als het bestaat en niet leeg is
                if 'description' in field_data and is_nonempty_str(field_data.get('description')):
                    field_context = context if context else description_context
                    t = safe_translate(field_data['description'], field_context)
                    if t:
                        translated_config[field_config][field_name]['description'] = t

                # Vertaal context als het bestaat en niet leeg is
                if 'context' in field_data and is_nonempty_str(field_data.get('context')):
                    t = safe_translate(field_data['context'], context)
                    if t:
                        translated_config[field_config][field_name]['context'] = t

                # vertaal allowed_values als het veld bestaat en waarden niet leeg zijn (alleen string-items)
                if 'allowed_values' in field_data and isinstance(field_data['allowed_values'], list) and field_data['allowed_values']:
                    translated_allowed_values = []
                    for allowed_value in field_data['allowed_values']:
                        if is_nonempty_str(allowed_value):
                            t = safe_translate(allowed_value, context)
                            translated_allowed_values.append(t if t else allowed_value)
                        else:
                            translated_allowed_values.append(allowed_value)
                    if translated_allowed_values:
                        translated_config[field_config][field_name]['allowed_values'] = translated_allowed_values

                # Vertaal meta.consentRich en meta.aria*
                meta = field_data.get('meta')
                if isinstance(meta, dict):
                    # consentRich
                    if is_nonempty_str(meta.get('consentRich')):
                        consent_ctx = (context if context else description_context) or ''
                        consent_ctx = f"Consent rich text with inline tags. Keep tag names intact and translate only inner text. {consent_ctx}".strip()
                        t = safe_translate(meta['consentRich'], consent_ctx)
                        if t and tags_valid(meta['consentRich'], t):
                            translated_config[field_config][field_name].setdefault('meta', {})['consentRich'] = t
                            meta_consentRich_translated_count += 1
                        else:
                            if t and not tags_valid(meta['consentRich'], t) and current_event:
                                src_counts = extract_tag_counts(meta['consentRich'])
                                dst_counts = extract_tag_counts(t)
                                current_event.log_error('inline_tags_validation_failed', {
                                    'tenant_id': tenant_id,
                                    'config_type': config_type,
                                    'config_version': config_version,
                                    'field_config': field_config,
                                    'field_name': field_name,
                                    'target_language': target_language,
                                    'source_tag_counts': src_counts,
                                    'translated_tag_counts': dst_counts
                                })
                                meta_inline_tags_invalid_after_translation_count += 1
                            # fallback: keep original (already in deep copy)
                    # aria*
                    for k, v in list(meta.items()):
                        if isinstance(k, str) and k.startswith('aria') and is_nonempty_str(v):
                            aria_ctx = (context if context else description_context) or ''
                            aria_ctx = f"ARIA label for accessibility. Short, imperative, descriptive. Form '{config_type} {config_version}', field '{field_name}'. {aria_ctx}".strip()
                            t2 = safe_translate(v, aria_ctx)
                            if t2:
                                translated_config[field_config][field_name].setdefault('meta', {})[k] = t2
                                meta_aria_translated_count += 1

            return translated_config

    @staticmethod
    def translate(tenant_id: int, text: str, target_language: str, source_language: Optional[str] = None,
                  context: Optional[str] = None)-> str:
        if current_event:
            with current_event.create_span('Translation'):
                translation_cache = cache_manager.translation_cache.get_translation(text, target_language,
                                                                                    source_language, context)
                return translation_cache.translated_text
        else:
            with BusinessEvent('Translation Service', tenant_id):
                with current_event.create_span('Translation'):
                    translation_cache = cache_manager.translation_cache.get_translation(text, target_language,
                                                                                        source_language, context)
                    return translation_cache.translated_text