import re
from typing import Dict, List, Tuple

email_ending_part = {
    ".com": {"bn": "ডট কম।", "en": "dot com"},
    ".org": {"bn": "ডট ও আর জি।", "en": "dot org"},
    ".net": {"bn": "ডট নেট।", "en": "dot net"},
    ".edu": {"bn": "ডট এডু।", "en": "dot edu"},
    ".gov": {"bn": "ডট গভ।", "en": "dot gov"},
    ".bd": {"bn": "ডট বিডি।", "en": "dot bd"},
    # ⭐ Modern & Very Popular Global TLDs
    ".io": {"bn": "ডট আই, ও।", "en": "dot io"},
    ".co": {"bn": "ডট কো। ", "en": "dot co"},
    ".me": {"bn": "ডট মি।", "en": "dot me"},
    ".info": {"bn": "ডট ইনফো।", "en": "dot info"},
    ".xyz": {"bn": "ডট এক্স-ওয়াই-জেড।", "en": "dot xyz"},
    ".biz": {"bn": "ডট বিজ।", "en": "dot biz"},
    # ⭐ Very Common Country TLDs (Emails, companies, gov)
    ".uk": {"bn": "ডট ইউকে।", "en": "dot uk"},
    ".de": {"bn": "ডট ডি, ই।", "en": "dot de"},
    ".fr": {"bn": "ডট এফ আর।", "en": "dot fr"},
    ".in": {"bn": "ডট ইন।", "en": "dot in"},
    ".au": {"bn": "ডট এ, ইউ।", "en": "dot au"},
    ".ca": {"bn": "ডট সি, এ।", "en": "dot ca"},
    # ⭐ Email-heavy Asia TLDs
    ".co.jp": {"bn": "ডট কো ডট জে, পি।", "en": "dot co dot jp"},
    ".jp": {"bn": "ডট জে, পি।", "en": "dot jp"},
    ".cn": {"bn": "ডট সি, এন।", "en": "dot cn"},
    ".sg": {"bn": "ডট এস, জি।", "en": "dot sg"},
    # ⭐ Security & Tech Popular Domains
    ".dev": {"bn": "ডট ডেভ।", "en": "dot dev"},
    ".app": {"bn": "ডট অ্যাপ।", "en": "dot app"},
}

email_replace_unit = {
    "@": {"en": "at the rate", "bn": "অ্যাট দ্য রেট"},
    ":": {"en": "colon", "bn": "কলন"},
    "/": {"en": "slash", "bn": "স্ল্যাশ"},
    "_": {"en": "underscore", "bn": "আন্ডার স্কোর,"},
    ".": {"en": "dot", "bn": "ডট"},
}

url_replace_unit = {
    "http://": {"bn": "এইচ, টি, টি, পি। কোলন ডাবল স্ল্যাশ।", "en": "http clone. double slash"},
    "https://": {
        "bn": "এইচ, টি, টি, পি, এস। কোলন ডাবল স্ল্যাশ।",
        "en": "https clone. double slash",
    },
    "ftp://" : {"bn": "এফ, টি, পি। কোলন ডাবল স্ল্যাশ।", "en": "FTP clone. double slash"},
    "ws://" : {"bn": "ডাবলু, এস। কোলন ডাবল স্ল্যাশ।", "en": "WS clone. double slash"},
    "wss://" : {"bn": "ডাবলু, এস, এস। কোলন ডাবল স্ল্যাশ।", "en": "WSS clone. double slash"},
    "file://" : {"bn": "ফাইল, কোলন ডাবল স্ল্যাশ।", "en": "File clone. double slash"},
    "www.": {"bn": "ডব্লিউ, ডব্লিউ, ডব্লিউ, ডট। ", "en": "www dot"},
    ".com": {"bn": "ডট কম। ", "en": "dot com"},
    ".org": {"bn": "ডট ও আর জি। ", "en": "dot org"},
    ".net": {"bn": "ডট নেট। ", "en": "dot net"},
    ".edu": {"bn": "ডট এডু। ", "en": "dot edu"},
    ".gov": {"bn": "ডট গভ। ", "en": "dot gov"},
    ".bd": {"bn": "ডট বিডি। ", "en": "dot bd"},
    # ⭐ Modern & Very Popular Global TLDs
    ".io": {"bn": "ডট আই, ও। ", "en": "dot io"},
    ".co": {"bn": "ডট কো। ", "en": "dot co"},
    ".me": {"bn": "ডট মি। ", "en": "dot me"},
    ".info": {"bn": "ডট ইনফো। ", "en": "dot info"},
    ".xyz": {"bn": "ডট এক্স-ওয়াই-জেড। ", "en": "dot xyz"},
    ".biz": {"bn": "ডট বিজ। ", "en": "dot biz"},
    # ⭐ Very Common Country TLDs (Emails, companies, gov)
    ".uk": {"bn": "ডট ইউকে। ", "en": "dot uk"},
    ".de": {"bn": "ডট ডি, ই।", "en": "dot de"},
    ".fr": {"bn": "ডট এফ আর।", "en": "dot fr"},
    ".in": {"bn": "ডট ইন।", "en": "dot in"},
    ".au": {"bn": "ডট এ, ইউ।", "en": "dot au"},
    ".ca": {"bn": "ডট সি, এ।", "en": "dot ca"},
    # ⭐ Email-heavy Asia TLDs
    ".co.jp": {"bn": "ডট কো ডট জে, পি।", "en": "dot co dot jp"},
    ".jp": {"bn": "ডট জে, পি। ", "en": "dot jp"},
    ".cn": {"bn": "ডট সি, এন। ", "en": "dot cn"},
    ".sg": {"bn": "ডট এস, জি। ", "en": "dot sg"},
    # ⭐ Security & Tech Popular Domains
    ".dev": {"bn": "ডট ডেভ। ", "en": "dot dev"},
    ".app": {"bn": "ডট অ্যাপ। ", "en": "dot app"},
    # Others
    "/": {"bn": "স্ল্যাশ। ", "en": "slash"},
    "-": {"bn": "ড্যাশ,", "en": "dash"},
    "_": {"bn": "আন্ডার স্কোর,", "en": "underscore"},
    "@": {"bn": "অ্যাট,", "en": "at"},
    ".": {"bn": "ডট,", "en": "dot"},
    ":": {"bn": "কোলন,", "en": "colon"},
    "=": {"bn": "একুয়াল,", "en": "equals"},
    "?": {"bn": "কোয়েশ্চেন মার্ক,", "en": "question mark"},
    "&": {"bn": "এন্ড,", "en": "and"},
    "%": {"bn": "পারসেন্ট,", "en": "percent"},
    "#": {"bn": "হ্যাশ", "en": "hash"},
}

bn_number_map = {
    "0": "জিরো",
    "1": "ওয়ান",
    "2": "টু",
    "3": "থ্রি",
    "4": "ফোর",
    "5": "ফাইভ",
    "6": "সিক্স",
    "7": "সেভেন",
    "8": "এইট",
    "9": "নাইন",
    "০": "শূন্য",
    "১": "এক",
    "২": "দুই",
    "৩": "তিন",
    "৪": "চার",
    "৫": "পাঁচ",
    "৬": "ছয়",
    "৭": "সাত",
    "৮": "আট",
    "৯": "নয়",
}

en_number_map = {
    "0": "zero",
    "1": "one",
    "2": "two",
    "3": "three",
    "4": "four",
    "5": "five",
    "6": "six",
    "7": "seven",
    "8": "eight",
    "9": "nine",
}


class EmailURLExtractor:
    def __init__(self):
        # Email regex pattern
        self.email_pattern = re.compile(r"\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b")

        # URL regex pattern (handles http, https, ftp, and www)
        self.url_pattern = re.compile(
            r"(?:(?:https?|ftp):\/\/)?"  # Optional protocol
            r"(?:www\.)?"  # Optional www
            r"(?:[A-Za-z0-9](?:[A-Za-z0-9-]{0,61}[A-Za-z0-9])?\.)+"  # Domain
            r"[A-Za-z]{2,}"  # Top-level domain
            r"(?::[0-9]{1,5})?"  # Optional port
            r"(?:\/[^\s]*)?"  # Optional path
        )

    def normalize_url(self, url: str, lang="bn") -> str:
        """Normalize URL for better pronunciation."""
        normalized = url

        # Replace URL components
        for component, replacement in url_replace_unit.items():
            # print("component : ", component, " replacement : ", replacement)
            normalized = normalized.replace(component, f" {replacement[lang]} ")

        # Clean up extra spaces
        normalized = " ".join(normalized.split())

        return normalized.strip()

    def replace_numbers(self, normalized_url: str, lang="bn") -> str:
        number_matchs = re.findall(r"\d+", normalized_url)
        # print("number_match : ", number_matchs)

        if number_matchs:
            for number_match in number_matchs:
                number_str = number_match
                # number_str = number_match.group()
                if lang == "bn":
                    normalized_number = " ".join(
                        bn_number_map.get(digit, digit) for digit in number_str
                    )
                else:
                    normalized_number = " ".join(
                        en_number_map.get(digit, digit) for digit in number_str
                    )
                normalized_url = normalized_url.replace(number_str, " " + normalized_number + " ")
        # Replace the original number string with the normalized version
        return normalized_url

    def extract_emails(self, text: str, lang="bn") -> str:
        # Replace URL components
        for component, replacement in url_replace_unit.items():
            normalized = normalized.replace(component, replacement)

        # Clean up extra spaces
        normalized = " ".join(normalized.split())

        return normalized.strip()

    def email_normalization(self, text: str, lang="bn") -> str:
        """Extract all email addresses from the text and replace them with normalized versions."""

        # Extract emails with their spans using finditer instead of findall
        email_matches = []
        for match in self.email_pattern.finditer(text):
            email_matches.append(
                {
                    "email": match.group(),
                    "span": match.span(),  # (start, end) positions
                    "start": match.start(),
                    "end": match.end(),
                }
            )

        # print("Extracted emails with spans: ", [(m['email'], m['span']) for m in email_matches])

        # Sort matches in reverse order by start position to avoid position shifts during replacement
        email_matches.sort(key=lambda x: x["start"], reverse=True)

        # Process and replace each email
        for match in email_matches:
            email = match["email"]
            start = match["start"]
            end = match["end"]

            # Normalize email for pronunciation
            normalized_email = email

            if "@" in normalized_email and lang == "bn":
                normalized_email = normalized_email.replace("@", "।@")

            for char, replacement in email_ending_part.items():
                if normalized_email.endswith(char):
                    normalized_email = normalized_email[: -len(char)] + f" {replacement[lang]} "

            for char, replacement in email_replace_unit.items():
                if char in normalized_email:
                    normalized_email = normalized_email.replace(char, f" {replacement[lang]} ")

            normalized_email = normalized_email.strip()
            print(f"Normalizing: {email} -> {normalized_email}")

            normalized_email = self.replace_numbers(normalized_email, lang)

            # Replace in text using span
            text = text[:start] + " " + normalized_email + " " + text[end:]

        return text

    def url_normalization(self, text: str, lang="bn") -> str:
        """Extract all URLs from the text and replace them with normalized versions."""

        # Extract URLs with their spans using finditer
        url_matches = []
        for match in self.url_pattern.finditer(text):
            url_matches.append(
                {
                    "url": match.group(),
                    "span": match.span(),
                    "start": match.start(),
                    "end": match.end(),
                }
            )

        # print("Extracted URLs with spans: ", [(m['url'], m['span']) for m in url_matches])

        # Sort matches in reverse order by start position
        url_matches.sort(key=lambda x: x["start"], reverse=True)

        # Process and replace each URL
        for match in url_matches:
            url = match["url"]
            start = match["start"]
            end = match["end"]
            # Normalize URL for pronunciation
            normalized_url = self.normalize_url(url, lang)
            # print(f"Normalizing URL: {url} -> {normalized_url}")

            # extract number from url and replace with words
            normalized_url = self.replace_numbers(normalized_url, lang)

            # Replace in text using span
            text = text[:start] + normalized_url + text[end:]
        return text


# Example usage
if __name__ == "__main__":
    # Test sentences
    test_texts = [
        "Contact us at info@example.com or visit https://www.example.com",
        "Send email to john.doe@company.org and check www.company.org/about",
        "Multiple contacts: sales@site.com, support@site.co.uk, marketing@site.net",
        "Visit http://github.com/user/repo or ftp://files.server.com",
        "My email is test.user+tag@gmail.com and website is example.io",
        "Check out https://subdomain.example.com:8080/path/to/page?query=1",
    ]

    # Using the class
    # print("Using EmailURLExtractor class:")
    # print("-" * 50)
    lang = "bn"
    extractor = EmailURLExtractor()
    for text in test_texts:
        print(f"\nText: {text}")
        text = extractor.email_normalization(text, lang=lang)
        text = extractor.url_normalization(text, lang=lang)

        print(f"output text : {text}")
        print("----------------------")
        # print(f"URLs: {urls}")
