import re
from typing import Dict, List, Optional, Tuple

from num2words import num2words

from .number_pronunciation import normalize_with_3_pattern


class NumberNormalizationService:
    def __init__(self):
        # Bengali to English digit mapping
        self.mapping_normalization = {
            "0": "জিরো",
            "1": "ওয়ান",
            "2": "টু",
            "3": "থ্রি",
            "4": "ফোর",
            "5": "ফাইভ",
            "6": "সিক্স",
            "7": "সেভেন",
            "8": "এইট",
            "9": "নাইন",
            "০": "শূন্য",
            "১": "এক",
            "২": "দুই",
            "৩": "তিন",
            "৪": "চার",
            "৫": "পাঁচ",
            "৬": "ছয়",
            "৭": "সাত",
            "৮": "আট",
            "৯": "নয়",
        }

        # Month names in Bengali and English
        self.month_names = [
            "জানুয়ারি",
            "ফেব্রুয়ারি",
            "মার্চ",
            "এপ্রিল",
            "মে",
            "জুন",
            "জুলাই",
            "আগস্ট",
            "সেপ্টেম্বর",
            "অক্টোবর",
            "নভেম্বর",
            "ডিসেম্বর",
            "january",
            "february",
            "march",
            "april",
            "may",
            "june",
            "july",
            "august",
            "september",
            "october",
            "november",
            "december",
            "jan",
            "feb",
            "mar",
            "apr",
            "may",
            "jun",
            "jul",
            "aug",
            "sep",
            "oct",
            "nov",
            "dec",
        ]

        # Date pattern to exclude from normalization
        # Matches 1-2 digits (date) followed by month name
        self.date_pattern = r"([০-৯\d]{1,2})\s*(" + "|".join(self.month_names) + r")"

        # self.passport_pattern = r'(?i)(?:e-passport|ই-পাসপোর্ট|e\s+passport|ই\s+পাসপোর্ট|passport|পাসপোর্ট)\s*(?:id|আইডি|নম্বর|নাম্বার|নং|number|no)?\s*[:=\-]?\s*([A-Za-z\u0985-\u09B9]?[\s\-]?[\u09E6-\u09EF0-9]+)'
        self.passport_pattern = r"(?i)(?:e-passport|ই-পাসপোর্ট|e\s+passport|ই\s+পাসপোর্ট|passport|পাসপোর্ট)\s*(?:id|আইডি|নম্বর|নাম্বার|নং|number|no)?\s*[:=\-]?\s*([A-Za-z\u0985-\u09B9]?[\s\-]?[\u09E6-\u09EF0-9]{7,9}(?:\s*ও\s*[A-Za[z\u0985-\u09B9]?[\s\-]?[\u09E6-\u09EF0-9]{7,9})*)"

        self.number_pattern = r"([A-Za-z\u0985-\u09B9]?[\s\-]?[\u09E6-\u09EF0-9]{7,9})"

        self.field_patterns = [
            # Account variations (label REQUIRED)
            (
                r"(?i)(ভোটার|একাউন্ট|account|a/c|A/C|a c|A C|acc|acct|হিসাব)\s*"
                r"(?:নম্বর|নাম্বার|নং|ন\.|number|no\.?|id|আইডি\.?)\s*:?\s*"
                r"(?P<account_number>[০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "account_number",
            ),
            # Receipt variations (label REQUIRED)
            (
                r"(?i)(রিসিপ্ট|রশিদ|রসিদ|receipt|ricipt|rcpt|rec)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|id|আইডি\.?)\s*:?\s*"
                r"(?P<receipt_number>[০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "receipt_number",
            ),
            # Transaction variations (label REQUIRED)
            (
                r"(?i)(ট্রানজেকশন|লেনদেন|টিকেট|transaction|transcription|trans|txn|trx)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|id|আইডি\.?)\s*:?\s*"
                r"(?P<transaction_number>[০-৯0-9][০-৯0-9\-\.\স]*[০-৯0-9])",
                "transaction_number",
            ),
            # Slip variations (label REQUIRED)
            (
                r"(?i)(শ্লিপ|স্লিপ|চেক|slip|cilip)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|আইডি|id\.?)\s*:?\s*"
                r"(?P<slip_number>[০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "slip_number",
            ),
            # Card variations (label REQUIRED)
            (
                r"(?i)(কার্ড|card)\s*"
                r"(?:নম্বর|নাম্বার|number|নং|no\.?|id|আইডি\.?)\s*:?\s*"
                r"(?P<card_number>[০০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "card_number",
            ),
            # Token variations (label REQUIRED)
            (
                r"(?i)(টোকেন|token)(?:\s*id)?\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|আইডি|id\.?)\s*:?\s*"
                r"(?P<token_number>[০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "token_number",
            ),
            # Bill variations (label REQUIRED)
            (
                r"(?i)(বিল|bill)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|আইডি|id\.?)\s*:?\s*"
                r"(?P<bill_number>[০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "bill_number",
            ),
            # Invoice variations — alphanumeric allowed (label REQUIRED)
            (
                r"(?i)(চালান|ইনভয়েস|invoice|inv)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|আইডি|id\.?)\s*:?\s*"
                r"(?P<invoice_number>[A-Z0-9০-৯][A-Z0-9০-৯\-\.\s]*[A-Z0-9০-৯])",
                "invoice_number",
            ),
            # Voucher variations (label REQUIRED)
            (
                r"(?i)(ভাউচার|voucher)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|আইডি|id\.?)\s*:?\s*"
                r"(?P<voucher_number>[০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "voucher_number",
            ),
            # Order variations — alphanumeric allowed (label REQUIRED)
            (
                r"(?i)(অর্ডার|order)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|আইডি|id\.?)\s*:?\s*"
                r"(?P<order_number>[A-Z0-9০-৯][A-Z0-9০-৯\-\.\s]*[A-Z0-9০-৯])",
                "order_number",
            ),
            # Reference variations — alphanumeric allowed (label REQUIRED)
            (
                r"(?i)(রেফারেন্স|reference|ref)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|আইডি|id\.?)\s*:?\s*"
                r"(?P<reference_number>[A-Z0-9০-৯][A-Z0-9০-৯\-\.\s]*[A-Z0-9০-৯])",
                "reference_number",
            ),
            # Payment variations (label REQUIRED now)
            (
                r"(?i)(পেমেন্ট|payment)\s*"
                r"(?:id|আইডি|নম্বর|নাম্বার|number|no\.?)\s*:?\s*"
                r"(?P<payment_id>[০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "payment_id",
            ),
            # Tracking variations — alphanumeric allowed (label REQUIRED)
            (
                r"(?i)(ট্র্যাকিং|tracking|track)\s*"
                r"(?:নম্বর|নাম্বার|নং|number|no\.?|আইডি|id\.?)\s*:?\s*"
                r"(?P<tracking_number>[A-Z0-9০-৯][A-Z0-9০-৯\-\.\s]*[A-Z0-9০-৯])",
                "tracking_number",
            ),
            # Customer variations (label REQUIRED)
            (
                r"(?i)(গ্রাহক|কাস্টমার|customer|cust)\s*"
                r"(?:id|আইডি|নম্বর|number|no\.?)\s*:?\s*"
                r"(?P<customer_id>[০-৯0-9][০-৯0-9\-\.\s]*[০-৯0-9])",
                "customer_id",
            ),
            # Passport variations — 1 optional letter (A–Z or Bengali) + digits (label REQUIRED)
            (
                r"(?i)(e-passport|ই-পাসপোর্ট|e passport|ই পাসপোর্ট|passport|পাসপোর্ট)\s*"
                r"(?:id|আইডি|নম্বর|নাম্বার|নং|number|no\.?)\s*:?-?\s*"
                r"(?P<passport_id>[A-Zএ-ঔঅ-হ]?[০-৯0-9]+)",
                "passport_id",
            ),
        ]

    def extract_passport_unicode(self, text):
        """
        Extract using Unicode ranges for Bengali characters
        Returns a list of dicts with passport number and its span
        """
        # Example: self.passport_pattern could be something like r"[A-Z0-9\u0985-\u09EF]{8,10}"
        matches = re.finditer(self.passport_pattern, text)

        sorted_matches = sorted(matches, key=lambda m: m.start(), reverse=True)

        # print("text 1.5 : ", text)

        # print("sorted_matches : ", sorted_matches)

        # extracted_passports = []
        for match in sorted_matches:
            string_pass = match.group(0)
            index_span = match.span()

            # print("Found passport number:", string_pass, " at position:", index_span)
            # Extract digits from the cleaned passport string
            # print("string_pass : ", string_pass)
            digits = re.findall(self.number_pattern, string_pass)

            # print("digits:", digits)
            for digit in digits:
                words = []
                for d in digit:
                    if d in self.mapping_normalization:
                        words.append(self.mapping_normalization[d])
                    else:
                        words.append(d)
                normalize_string = normalize_with_3_pattern(words)

                string_pass = string_pass.replace(digit, " " + normalize_string + " ")

            text = text[: index_span[0]] + " " + string_pass + " " + text[index_span[1] :]

        # if have multiple comma then replace with one comma
        text = re.sub(r",\s*,+", ", ", text)

        # print("text 1.5 : ", text)

        return text

    def extract_field_and_number_with_spans(
        self, text: str
    ) -> List[Tuple[str, str, str, Tuple[int, int]]]:
        """Extract field name, clean number, original number format and span position from text"""
        extractions = []

        for pattern, field_name in self.field_patterns:
            for match in re.finditer(pattern, text):
                # Find the last non-None group that contains numbers
                number_text_original = None
                number_start = None
                number_end = None

                for i in range(len(match.groups()), 0, -1):
                    group = match.group(i)
                    if group and re.search(r"[০-৯\d]", group):
                        number_text_original = group.strip()
                        # Get the span of this specific group
                        number_start = match.start(i)
                        number_end = match.end(i)
                        break

                if number_text_original and number_start is not None:
                    # For alphanumeric IDs, extract only the numeric part
                    # but keep the original format for replacement
                    numeric_parts = re.findall(r"[০-৯\d]+", number_text_original)
                    # print("numeric_parts : ", numeric_parts)
                    if numeric_parts:
                        # Join all numeric parts
                        clean_number = "".join(numeric_parts)
                        # Convert Bengali digits to English
                        # clean_number = self.convert_bengali_to_english(clean_number)

                        if clean_number:
                            # Adjust span to match the actual position of the number in the original text
                            actual_start = text.find(number_text_original, number_start)
                            if actual_start != -1:
                                actual_end = actual_start + len(number_text_original)
                                extractions.append(
                                    (
                                        field_name,
                                        clean_number,
                                        number_text_original,
                                        (actual_start, actual_end),
                                    )
                                )

        return extractions

    def extract_field_and_number(self, text: str) -> Optional[Tuple[str, str, str]]:
        """Extract field name, clean number, and original number format from text (backward compatibility)"""
        extractions = self.extract_field_and_number_with_spans(text)
        if extractions:
            return extractions[0][:3]  # Return first match without span
        return None

    def convert_bengali_to_english(self, text: str) -> str:
        """Convert Bengali digits to English digits"""
        bengali_to_english = {
            "০": "0",
            "১": "1",
            "২": "2",
            "৩": "3",
            "৪": "4",
            "৫": "5",
            "৬": "6",
            "৭": "7",
            "৮": "8",
            "৯": "9",
        }
        for bengali, english in bengali_to_english.items():
            text = text.replace(bengali, english)
        return text

    def number_to_words_with_format(self, number: str, original_format: str) -> str:
        """Convert number to words while preserving the original format structure"""
        # If the original has a prefix (like INV-, ORD-, etc.), preserve it
        prefix_match = re.match(r"^([A-Z]+-)", original_format)
        prefix = prefix_match.group(1) if prefix_match else ""

        # Convert the numeric part to words
        words = []
        for digit in number:
            if digit in self.mapping_normalization:
                words.append(self.mapping_normalization[digit])
            else:
                words.append(digit)
        normalize_string = normalize_with_3_pattern(words)

        if prefix:
            return prefix + normalize_string
        else:
            return normalize_string

    def date_patter_procesing(self, text: str):
        """Find positions of date numbers that should not be normalized"""
        exclude_positions = []

        matches = re.finditer(self.date_pattern, text, re.IGNORECASE)

        sorted_matches = sorted(matches, key=lambda m: m.start(), reverse=True)

        # Find all date patterns
        for match in sorted_matches:
            # Get the position of the date number
            word = match.group(1)
            date_start = match.start(1)
            date_end = match.end(1)
            exclude_positions.append((date_start, date_end))
            # print("Found date to exclude:", word)
            #  need to check bangla number or english number
            lang = "bn"
            if re.search(r"[০-৯]", word):
                lang = "bn"
                word_in_bengali = num2words(word, lang=lang)
            elif re.search(r"[0-9]", word):
                lang = "en"
                word_in_bengali = num2words(word, lang=lang)
                # word_in_bengali = cfg._bangla_numeric_words[word_in_en]

            # Replace the date number with its word form in the text
            text = text[:date_start] + " " + word_in_bengali + " " + text[date_end:]
            # print("Replaced date number with words:", text)

        return text

    def number_to_words(self, number: str) -> str:
        """Convert number digits to Bengali words"""
        words = []
        for digit in number:
            if digit in self.mapping_normalization:
                words.append(self.mapping_normalization[digit])
            else:
                words.append(digit)
        # print("words : ", words)

        normalize_string = normalize_with_3_pattern(words)

        return normalize_string

    def extract_number_with_spans_or_hypen(self, text):
        """Extract numbers with hyphens or spaces"""
        extractions = []
        # Pattern that matches digits with hyphens or spaces between them
        pattern = r"\b(\d+(?:[-\s]\d+)+)\b"

        for match in re.finditer(pattern, text):
            # This will match "987-654-3210" but NOT the text after it
            original_number_format = match.group(1)
            clean_number = re.sub(r"[-\s]", "", original_number_format)

            extractions.append((clean_number, original_number_format))

        return extractions

    def replace_numbers_with_words(self, text: str) -> str:
        """Replace numbers in text with Bengali words using span-based replacement"""
        # Handle date pattern processing first
        text = self.date_patter_procesing(text)

        text = self.extract_passport_unicode(text)

        # print("text1.5 :" , text)

        lines = text.split("\n")
        processed_lines = []

        for line in lines:
            processed_line = line

            # Extract all field and number matches with spans
            extractions = self.extract_field_and_number_with_spans(line)

            # print("extractions with spans: ", extractions)

            if extractions:
                # Sort extractions by span position in reverse order to prevent index shifting
                sorted_extractions = sorted(extractions, key=lambda x: x[3][0], reverse=True)

                # print("sorted_extractions: ", sorted_extractions)

                # Process each extraction from right to left
                for field_name, clean_number, original_number_format, span in sorted_extractions:
                    start_pos, end_pos = span
                    # print("original_number_format : ", extract_number_with_spans_or_hypen, clean_number)
                    number_extract = self.extract_number_with_spans_or_hypen(
                        original_number_format
                    )
                    # Check if the original format has a letter prefix
                    if re.match(r"^[A-Z]+-", original_number_format):
                        #     # Use special formatting for alphanumeric IDs
                        words = self.number_to_words_with_format(
                            clean_number, original_number_format
                        )
                    else:
                        #     # Regular number conversion
                        words = self.number_to_words(clean_number)

                    if number_extract and number_extract[0][0] == clean_number:
                        r_original_number_format = original_number_format.replace(
                            number_extract[0][1], words
                        )
                        processed_line = processed_line.replace(
                            original_number_format, r_original_number_format
                        )
                    else:
                        processed_line = processed_line.replace(original_number_format, words)
            processed_lines.append(processed_line)

        return " ".join(processed_lines)


# Example usage
if __name__ == "__main__":
    service = NumberNormalizationService()

    # Test the problematic cases
    #     test_cases = [
    #     "একাউন্ট নম্বর ১২৩৪৫৬৬",
    #     "account number 1234567890",
    #     "রিসিপ্ট  নম্বর 123452",
    #     "ricipt number 123456677989",
    #     "রশিদ  নম্বর 8904390",
    #    " ট্রানজেকশন নাম্বার 893023",
    #     "transcrition number 12338902983",
    #     "শ্লিপ নম্বর 1234567890123",
    #     "cilip number 1234567890123",
    #     "card number 1234567890123",
    #     "token id number 1234567890123",
    #     "টোকেন নম্বর  ৪৫৬৭৮০৩৪৫",
    #     "বিল নম্বর  ৪৫৬৭৮০৩৪৫ hello how are you",
    #     "bill number 456780345",
    #     "চালান নম্বর  ৪৫৬৭৮০৩৪৫",
    #     "invoice number 456780345",
    #     "আমার একাউন্ট নম্বর ১২৩৪৫৬৭৮৯০ থেকে টাকা কেটে নিয়েছে।",
    #     "Please transfer the amount to account number 1234567890 before 5 PM.",
    #     "গ্রাহকের A/C নং: ৯৮৭৬৫৪৩২১০ এ জমা করুন।",
    #     "Your savings acc no. 123-456-7890 has been credited with BDT 5000.",
    #     "আপনার হিসাব নাম্বার: ১২৩৪ ৫৬৭৮ ৯০১২ সফলভাবে খোলা হয়েছে।",
    #     "The loan amount will be deducted from ACCT NUMBER: 1234.5678.9012 monthly.",
    #     "আপনার একাউন্ট নম্বর ১২৩৪৫৬৬ সংরক্ষণ করুন।",
    #     "Account No. 987-654-3210 is linked to your mobile number.",
    #     "আপনার রিসিপ্ট নম্বর ৪৫৬৭৮৯০১২৩ সংরক্ষণ করুন ভবিষ্যতের জন্য।",
    #     "রশিদ নং: ১২৩৪৫৬ দেখিয়ে আপনার পণ্য সংগ্রহ করুন।",
    #     "মূল রসিদ নাম্বার ৯৮৭-৬৫৪-৩২১ ছাড়া রিটার্ন সম্ভব নয়।",
    #     "Your payment receipt number: 123456789 has been generated successfully.",
    #     "অনুগ্রহ করে Ricipt Number 876543210 টি প্রিন্ট করে রাখুন।",
    #     "The rcpt no. 555-666-777 is required for warranty claims.",
    #     "আপনার রিসিপ্ট নম্বর ৪৫৬৭৮৯০১২৩ সংরক্ষণ করুন ভবিষ্যতের জন্য।",
    #     "রশিদ নং: ১২৩৪৫৬ দেখিয়ে আপনার পণ্য সংগ্রহ করুন।",
    #     "মূল রসিদ নাম্বার ৯৮৭-৬৫৪-৩২১ ছাড়া রিটার্ন সম্ভব নয়।",
    #     "Your payment receipt number: 123456789 has been generated successfully.",
    #     "অনুগ্রহ করে Ricipt Number 876543210 টি প্রিন্ট করে রাখুন।",
    #     "The rcpt no. 555-666-777 is required for warranty claims.",
    #     "আপনার রিসিপ্ট নম্বর ৪৫৬৭৮৯০১২৩ সংরক্ষণ করুন ভবিষ্যতের জন্য।",
    #     "রশিদ নং: ১২৩৪৫৬ দেখিয়ে আপনার পণ্য সংগ্রহ করুন।",
    #     "মূল রসিদ নাম্বার ৯৮৭-৬৫৪-৩২১ ছাড়া রিটার্ন সম্ভব নয়।",
    #     "Your payment receipt number: 123456789 has been generated successfully.",
    #     "অনুগ্রহ করে Ricipt Number 876543210 টি প্রিন্ট করে রাখুন।",
    #     "The rcpt no. 555-666-777 is required for warranty claims.",
    #     "আপনার ট্রানজেকশন নম্বর 891২৩৪৫৬৭৮ দিয়ে অভিযোগ করুন।",
    #     "আজকের লেনদেন নং: ৭৮৯০১২৩৪৫৬ সফল হয়েছে।",
    #     "Your transaction number 123456789012 has been processed at 2:30 PM.",
    #     "Failed transcrition number 999-888-777-666 will be reversed within 7 days.",
    #     "দয়া করে Trans No. ৬৫৪৩২১০৯৮৭ রেফারেন্স হিসাবে ব্যবহার করুন।",
    #     "TXN নাম্বার: 111222333444 এর জন্য ১০ টাকা চার্জ কাটা হয়েছে।",
    #     "আপনার ট্রানজেকশন নম্বর 891২৩৪৫৬৭৮ দিয়ে অভিযোগ করুন।",
    #     "আজকের লেনদেন নং: ৭৮৯০১২৩৪৫৬ সফল হয়েছে।",
    #     "Your transaction number 123456789012 has been processed at 2:30 PM.",
    #     "Failed transcrition number 999-888-777-666 will be reversed within 7 days.",
    #     "ব্যাংক শ্লিপ নম্বর ৩৪৫৬৭৮৯০১২ জমা দেওয়া হয়েছে।",
    #     "আপনার জমা স্লিপ নং: ৯৮৭৬৫৪৩২১০ অনুমোদন করা হয়েছে।",
    #     "Please keep the deposit slip number 123-456-789 for your records.",
    #     "উত্তোলন cilip number 555666777888 প্রসেসিং এ আছে।",
    #     "Deposit slip no. 123456789012 has been verified.",
    #     "আপনার শ্লিপ নম্বর ৩৪৫৬৭৮৯০১২ জমা দেওয়া হয়েছে।",
    #     "আপনার কার্ড নম্বর ১২৩৪৫৬৭৮৯০১২৩ দিয়ে পেমেন্ট সফল হয়েছে।",
    #     "Card number 9876-5432-1098-7654 is valid until 12/25.",
    #     "আপনার কার্ড নম্বর ৪৫৬৭ ৮৯০১ ২৩৪৫ ৬৭৮৯ দিয়ে পেমেন্ট করুন।",
    #     "Your new card number 1234-5678-9012-3456 will be activated within 24 hours.",
    #     "অনুগ্রহ করে Card নং ৯৮৭৬৫৪৩২১০৯৮৭৬ এর CVV দিন।",
    #     "Credit card no. 1234 5678 9012 3456 has been blocked due to suspicious activity.",
    #     "আপনার কার্ড নম্বর ১২৩৪৫৬৭৮৯০১২৩ দিয়ে পেমেন্ট সফল হয়েছে।",
    #     "Card number 9876-5432-1098-7654 is valid until 12/25.",
    #     "আপনার কার্ড নম্বর ৪৫৬৭ ৮৯০১ ২৩৪৫ ৬৭৮৯ দিয়ে পেমেন্ট করুন।",
    #     "Your new card number 1234-5678-9012-3456 will be activated within 24 hours.",
    #     "অনুগ্রহ করে Card নং ৯৮৭৬৫৪৩২১০৯৮৭৬ এর CVV দিন।",
    #     "Credit card no. 1234 5678 9012 3456 has been blocked due to suspicious activity.",
    #     "আপনার টোকেন নম্বর ৫৬৭৮৯০১২৩৪ দিয়ে লগইন করুন।",
    #     "Security token ID number 123456789012 expires at midnight.",
    #     "নতুন Token নং: ৯৮৭-৬৫৪-৩২১ জেনারেট করা হয়েছে।",
    #     "আপনার টোকেন নম্বর ৫৬৭৮৯০১২৩৪ দিয়ে লগইন করুন।",
    #     "এই মাসের বিল নম্বর ৮৯০১২৩৪৫৬৭ এর বকেয়া ৫০০০ টাকা।",
    #     "Your electricity bill number 202401-123456 is due on 15th January.",
    #     "বিল নং: ৭৮৯০১২৩৪৫৬ অনলাইনে পরিশোধ করা যাবে।",
    #     "আপনার বিদ্যুৎ বিল নম্বর ২০২৪০১-১২৩৪৫৬ ১৫ জানুয়ারি তারিখে পরিশোধ করতে হবে।",
    #     "আমাদের চালান নম্বর ৬৭৮৯০১২৩৪৫ অনুযায়ী পেমেন্ট করুন।",
    #     "Invoice number INV-2024-123456 has been sent to your email.",
    #     "মূল inv নং ৪৫৬৭৮৯০১২৩ ছাড়া পণ্য ফেরত নেওয়া হবে না।",
    #     "আপনার ইনভয়েস নম্বর ১২৩৪৫৬৭৮৯০১২ বৈধ।",
    #     "আপনার ভাউচার নম্বর ৩৪৫৬৭৮৯০১২ ৩১ ডিসেম্বর পর্যন্ত বৈধ।",
    #     "Gift voucher number 123-456-789-012 can be redeemed online.",
    #     "ভাউচার নং: ৯৮৭৬৫৪৩২১০ ব্যবহার করে ২০% ছাড় পাবেন।",
    #     "আপনার ভাউচার নম্বর ৩৪৫৬৭৮৯০১২ ৩১ ডিসেম্বর পর্যন্ত বৈধ।",
    #     "Gift voucher number 123-456-789-012 can be redeemed online.",
    #     "ভাউচার নং: ৯৮৭৬৫৪৩২১০ ব্যবহার করে ২০% ছাড় পাবেন।",
    #     "আপনার ভাউচার নম্বর ৩৪৫৬৭৮৯০১২ ৩১ ডিসেম্বর পর্যন্ত বৈধ।",
    #     "আপনার অর্ডার নম্বর ৮৯০১২৩৪৫৬৭ ট্র্যাক করুন।",
    #     "Your order number ORD-2024-123456 has been shipped today.",
    #     "অর্ডার নং: ৬৭৮৯০১২৩৪৫ এর ডেলিভারি ৩ দিনের মধ্যে হবে।",
    #     "আমার অর্ডার নাম্বার ১২৩৪৫৬৭৮৯০১২ বাতিল করতে চাই।",
    #     "Order No. 987-654-3210 has been delivered successfully.",
    #     "অর্ডার নম্বর: ৫৬৭৮৯০১২৩৪৫ এর ডেলিভারি ৩ দিনের মধ্যে হবে।",
    #     "দয়া করে রেফারেন্স নম্বর ৪৫৬৭৮৯০১২৩ উল্লেখ করুন।",
    #     "Use reference number REF-123-456-789 for all correspondence.",
    #     "আপনার Ref নং: ৯৮৭৬৫৪৩২১০ দিয়ে স্ট্যাটাস চেক করুন।",
    #     "পেমেন্ট আইডি ১২৩৪৫৬৭৮৯০১২ নিশ্চিত হয়েছে BDT ১০,০০০ এর জন্য।",
    #     "আপনার পেমেন্ট আইডি ৭৮৯০১২৩৪৫৬ সেভ করে রাখুন।",
    #     "Payment ID 123456789012 confirmed for BDT 10,000.",
    #     "পেমেন্ট নম্বর: ৫৬৭-৮৯০-১২৩ দিয়ে রিফান্ড ট্র্যাক করুন।",
    #     "আপনার ট্র্যাকিং নম্বর ১২৩৪৫৬৭৮৯০১২ দিয়ে পণ্য ট্র্যাক করুন।",
    #     "পার্সেল ট্র্যাকিং নম্বর ৬৭৮৯০১২৩৪৫৬৭৮ দিয়ে খুঁজুন।",
    #     "Your tracking number TRK-123-456-789-012 shows delivery tomorrow.",
    #     "ট্র্যাকিং নং: ৪৫৬৭৮৯০১২৩৪৫ অনলাইনে চেক করুন।",
    #     "আপনার ট্র্যাকিং নম্বর ১২৩৪৫৬৭৮৯০১২ দিয়ে পণ্য ট্র্যাক করুন।",
    #     "পার্সেল ট্র্যাকিং নম্বর ৬৭৮৯০১২৩৪৫৬৭৮ দিয়ে খুঁজুন।",
    #     "আপনার গ্রাহক আইডি ৯০১২৩৪৫৬৭৮ প্রোফাইলে আপডেট করুন।",
    "Customer ID 123456789012 is eligible for premium benefits.",
    #     "কাস্টমার নম্বর: ৭৮৯-০১২-৩৪৫৬ দিয়ে লগইন করুন।",
    #     "Your customer ID 123-456-789-012 is valid.",
    #     "আমার account নম্বর ১২৩৪৫৬৭৮৯০ থেকে টাকা transfer করুন।",
    #     "নতুন receipt নং: 987654321 জেনারেট হয়েছে।",
    #     "আপনার transaction নাম্বার ৫৬৭৮৯০ সফল হয়েছে।",
    #     "Havit HV-SC055 Laptop Cleaning Kit - HV-SC055 and the number is the 12345 and my acound amount is 1234567"
    #     ]

    test_cases = [
        # "hello পাসপোর্ট নম্বর ই১২৩৪৫৬৭৭, hi পাসপোর্ট নম্বর ই১২৩৪৫৬৭৭,",
        # "passport number: A12345678 and amar account number A23456781 ",
        # "ই-পাসপোর্ট আইডি: উ৯৮৭৬৫৪৩২",
        # "e-passport no: ক১২৩৪৫৬৭৮",
        # "পাসপোর্ট: অ৯৯৯৯৯৯৯৯",
        # "পাসপোর্ট নম্বর ই১২৩৪৫৬৭৭"
        # "পাসপোর্ট নম্বর স১২৩৪৫৬৭৭",
        # "hello পাসপোর্ট নম্বর ই১২৩৪৫৬৭৭, hi পাসপোর্ট নম্বর ই১২৩৪৫৬৭৭,",
        "Customer ID 123456789012 is eligible for premium benefits.",
        # "Your customer ID 123-456-789-012 is valid.",
        # "আমার পাসপোর্ট নম্বর A01234567 এবং তার পাসপোর্ট নম্বর 987654321।",
        # "নতুন ই-পাসপোর্ট নম্বর E12345678 ইস্যু করা হয়েছে।",
        # "তিনি পুরাতন পাসপোর্ট নম্বর 1234567 ব্যবহার করেছেন।",
        # "মেশিন রিডেবল পাসপোর্ট নম্বর B76543210।",
        # "তার পাসপোর্ট নম্বর P87654321 ছিল।",
        # "তার পাসপোর্ট নম্বর P০১২৩৪৫৬৭ ছিল।",
        # "বাংলা নম্বর হিসেবে পাসপোর্ট নম্বর এ০১২৩৪৫৬৭ ও ই১২৩৪৫৬৭৮।",
        # "পাসপোর্ট নম্বর এ০১২৩৪৫৬৭ ও ই১২৩৪৫৬৭৮।",
        # " ডিএসইতে লেনদেন ৩০০ কোটি টাকার নিচে নেমে এসেছে। লেনদেন হয়েছে ২৯০ কোটি ১৩ লাখ টাকার। গতকাল মঙ্গলবার লেনদেন হয়েছে ৩৩৯ কোটি ৭৫ লাখ টাকার।"
    ]

    print("Testing Alphanumeric Number Normalization\n")
    print("=" * 80)

    print("testing data : ", len(test_cases))

    for i, test_text in enumerate(test_cases):
        print("index : ", i)
        print(f"Input: {test_text}")
        replaced = service.replace_numbers_with_words(test_text)
        print(f"Output: {replaced}")
        print("-" * 80)
