
import re
from .num_to_words import num_to_words, ordinal_str
from .constants import NUMBER_WORDS, DATE_PRONUNCIATIONS

class BanglaTextNormalizer:
    def __init__(self):
        # Digit mapping for character-by-character conversion (like phone numbers)
        self.char_map = {
            '0': NUMBER_WORDS['0'][0], '1': NUMBER_WORDS['1'][0], 
            '2': NUMBER_WORDS['2'][0], '3': NUMBER_WORDS['3'][0], 
            '4': NUMBER_WORDS['4'][0], '5': NUMBER_WORDS['5'][0], 
            '6': NUMBER_WORDS['6'][0], '7': NUMBER_WORDS['7'][0], 
            '8': NUMBER_WORDS['8'][0], '9': NUMBER_WORDS['9'][0],
            '+': 'প্লাস'
        }
        
        self.months = {
            '01': 'জানুয়ারি', '02': 'ফেব্রুয়ারি', '03': 'মার্চ', '04': 'এপ্রিল',
            '05': 'মে', '06': 'জুন', '07': 'জুলাই', '08': 'আগস্ট',
            '09': 'সেপ্টেম্বর', '10': 'অক্টোবর', '11': 'নভেম্বর', '12': 'ডিসেম্বর',
            '1': 'জানুয়ারি', '2': 'ফেব্রুয়ারি', '3': 'মার্চ', '4': 'এপ্রিল',
            '5': 'মে', '6': 'জুন', '7': 'জুলাই', '8': 'আগস্ট',
            '9': 'সেপ্টেম্বর'
        }
        
        # ASCII translation table for Bangla digits
        self.bn_digits = '০১২৩৪৫৬৭৮৯'
        self.en_digits = '0123456789'
        self.translation_table = str.maketrans(self.bn_digits, self.en_digits)

    def text_cleaning(self, text):
        """Converts Bangla digits to English in the raw text."""
        return text.translate(self.translation_table)

    def _convert_num(self, n_str):
        """Wrapper to safely call the number converter."""
        try:
            return num_to_words(n_str)
        except Exception:
            return n_str

    def _char_by_char(self, digit_str):
        """Space-separated digit conversion."""
        return ' '.join([self.char_map.get(d, d) for d in digit_str])

    def _convert_day(self, day_str):
        """Standardizes day pronunciation."""
        # Convert "01" -> "1"
        key = str(int(day_str))
        if key in DATE_PRONUNCIATIONS:
            return DATE_PRONUNCIATIONS[key]
        return self._convert_num(day_str)

    def _convert_year_formatted(self, year_str):
        """
        Pronounces years like 19xx as 'Nineteen Hundred xx'.
        Standard conversion for other ranges (2000+).
        """
        if len(year_str) == 4:
            year_val = int(year_str)
            if 1100 <= year_val <= 1999:
                century = year_str[:2]
                decade = year_str[2:]
                
                c_text = self._convert_num(century)
                
                if decade == "00":
                    return f"{c_text}শো"
                else:
                    d_text = self._convert_num(decade)
                    return f"{c_text}শো {d_text}"
        
        return self._convert_num(year_str)

    def _process_date_match(self, match):
        day, _, month, year = match.groups()
        return f"{self._convert_day(day)} {self.months.get(month, month)} {self._convert_year_formatted(year)}"

    def _process_phone_match(self, match):
        raw = match.group(0)
        # Remove delimiters for digit processing
        cleaned = re.sub(r'[\s-]', '', raw)
        return self._char_by_char(cleaned)

    def _process_decimal_match(self, match):
        return num_to_words(match.group(0))
    
    def _process_fraction_match(self, match):
        num, den = match.group(1), match.group(2)
        if num == '1' and den == '2':
            return "অর্ধেক"
        return f"{self._convert_num(num)} বাই {self._convert_num(den)}"

    def _process_ordinal_match(self, match):
        return ordinal_str(match.group(1))

    def normalize(self, text):
        # 1. Standardize Digits
        text = self.text_cleaning(text)

        # 2. Phone Numbers
        # Pattern: Matches +88(opt) 01d (sep d)*8
        phone_pattern = r'(\+88)?\s*01[0-9](?:[\s-]*[0-9]){8}'
        text = re.sub(phone_pattern, self._process_phone_match, text)

        # 3. Dates
        date_pattern = r'\b(\d{1,2})([/\-])(\d{1,2})\2(\d{4})\b'
        text = re.sub(date_pattern, self._process_date_match, text)
        
        # 4. Ordinals
        # English style: 1st, 2nd, etc.
        text = re.sub(r'\b(\d+)(?:st|nd|rd|th)\b', self._process_ordinal_match, text, flags=re.IGNORECASE)
        # Bangla style suffix
        bn_ordinal_pattern = r'(\d+)(?:ম|য়|র্থ|ষ্ঠ|তম|য়)'
        text = re.sub(bn_ordinal_pattern, self._process_ordinal_match, text)

        # 5. Decimals
        text = re.sub(r'\b(\d+)\.(\d+)\b', self._process_decimal_match, text)
        
        # 6. Fractions
        text = re.sub(r'\b(\d+)/(\d+)\b', self._process_fraction_match, text)

        # 7. General Numbers
        text = re.sub(r'\d+', lambda m: self._convert_num(m.group(0)), text)

        return text
