"""E-posta adresi yardımcı fonksiyonları."""
from __future__ import annotations

import random
from typing import Iterable, List, Optional, Sequence, Tuple

_GMAIL_DOMAINS = {"gmail.com", "googlemail.com"}
_GMAIL_DOMAIN_ALIASES = _GMAIL_DOMAINS | {"gmail", "googlemail"}


def is_gmail_domain(domain_part: Optional[str]) -> bool:
    cleaned = str(domain_part or "").strip().lower()
    return cleaned in _GMAIL_DOMAINS


def is_gmail_domain_alias(domain_part: Optional[str]) -> bool:
    cleaned = str(domain_part or "").strip().lower()
    return cleaned in _GMAIL_DOMAIN_ALIASES


def is_gmail_address(email: str) -> bool:
    _, sep, domain_part = _split_email(email)
    return sep == "@" and is_gmail_domain(domain_part)


def _split_email(email: str):
    email = str(email or "").strip()
    if not email:
        return "", "", ""

    local_part, sep, domain_part = email.partition("@")
    if sep != "@" or not domain_part:
        return email, "", ""

    return local_part, sep, domain_part


def _split_local_plus_segment(local_part: str):
    main_part, plus_sep, plus_part = local_part.partition("+")
    return main_part, plus_sep, plus_part


def _extract_dot_positions(main_part: str) -> List[int]:
    positions: List[int] = []
    normalized_index = 0
    for char in main_part:
        if char == ".":
            positions.append(normalized_index)
        else:
            normalized_index += 1
    return positions


def _apply_dot_positions(normalized_main: str, positions: Sequence[int]) -> str:
    if not positions:
        return normalized_main

    sorted_unique = sorted({pos for pos in positions if 0 < pos < len(normalized_main)})
    if not sorted_unique:
        return normalized_main

    parts: List[str] = []
    last_index = 0
    for pos in sorted_unique:
        parts.append(normalized_main[last_index:pos])
        parts.append(".")
        last_index = pos
    parts.append(normalized_main[last_index:])
    return "".join(parts)


def _sanitize_history(
    history: Optional[Iterable[Iterable[int]]],
    normalized_length: int,
) -> List[List[int]]:
    if normalized_length <= 1:
        return []

    sanitized: List[List[int]] = []
    seen: set[Tuple[int, ...]] = set()

    if history is None:
        return sanitized

    for entry in history:
        if entry is None:
            continue
        try:
            values = [int(value) for value in entry]
        except (TypeError, ValueError):
            continue
        filtered = [
            value
            for value in values
            if 0 < value < normalized_length
        ]
        key = tuple(sorted(filtered))
        if not key or key in seen:
            continue
        seen.add(key)
        sanitized.append(list(key))
    return sanitized


def _all_single_dot_patterns(length: int) -> List[List[int]]:
    return [[index] for index in range(1, length)]


def extract_gmail_dot_positions(email: str) -> List[int]:
    local_part, sep, domain_part = _split_email(email)
    if sep != "@":
        return []

    if not is_gmail_domain(domain_part):
        return []

    main_part, _, _ = _split_local_plus_segment(local_part)
    return _extract_dot_positions(main_part)


def randomize_gmail_local_part(
    email: str,
    *,
    used_dot_positions: Optional[Iterable[Iterable[int]]] = None,
    advance_history: bool = True,
) -> Tuple[str, List[List[int]]]:
    """Gmail adreslerinin yerel kısmına nokta geçmişini dikkate alarak rastgeleleştir."""

    local_part, sep, domain_part = _split_email(email)
    original = str(email or "").strip()
    if not sep:
        return original, []

    if not is_gmail_domain(domain_part):
        return f"{local_part}{sep}{domain_part}", []

    main_part, plus_sep, plus_part = _split_local_plus_segment(local_part)
    normalized_main = main_part.replace(".", "")
    normalized_length = len(normalized_main)
    if normalized_length < 2:
        return f"{local_part}{sep}{domain_part}", []

    history = _sanitize_history(used_dot_positions, normalized_length)

    existing_pattern = _extract_dot_positions(main_part)
    if existing_pattern and existing_pattern not in history:
        history.append(existing_pattern)

    all_patterns = _all_single_dot_patterns(normalized_length)
    if not all_patterns:
        randomized_local = main_part
        if plus_sep:
            randomized_local += plus_sep + plus_part
        return f"{randomized_local}{sep}{domain_part}", history

    used_patterns = {tuple(item) for item in history}
    available = [pattern for pattern in all_patterns if tuple(pattern) not in used_patterns]

    last_pattern: Optional[List[int]] = history[-1] if history else None

    if not available:
        history = history[-1:] if history else []
        used_patterns = {tuple(item) for item in history}
        available = [pattern for pattern in all_patterns if tuple(pattern) not in used_patterns]
        if not available:
            available = all_patterns

    random.shuffle(available)
    chosen = available[0]

    if last_pattern is not None and chosen == last_pattern and len(available) > 1:
        chosen = available[1]

    randomized_main = _apply_dot_positions(normalized_main, chosen)
    randomized_local = randomized_main + (plus_sep + plus_part if plus_sep else "")

    if advance_history:
        history.append(list(chosen))

    return f"{randomized_local}{sep}{domain_part}", history


def ensure_local_part_has_dot(email: str) -> str:
    """Yerel kısmında nokta olmayan Gmail adreslerine deterministik nokta ekle."""

    local_part, sep, domain_part = _split_email(email)
    if not sep:
        return str(email or "").strip()

    if not is_gmail_domain(domain_part):
        return f"{local_part}{sep}{domain_part}"

    if "." in local_part:
        return f"{local_part}{sep}{domain_part}"

    main_part, plus_sep, plus_part = _split_local_plus_segment(local_part)
    normalized_main = main_part.replace(".", "")
    if len(normalized_main) <= 1:
        return f"{local_part}{sep}{domain_part}"

    insert_index = 1 if len(normalized_main) <= 3 else min(3, len(normalized_main) - 1)
    dotted_main = f"{normalized_main[:insert_index]}.{normalized_main[insert_index:]}"
    dotted_local = dotted_main + (plus_sep + plus_part if plus_sep else "")
    return f"{dotted_local}{sep}{domain_part}"


def remove_dots_from_local_part(email: str) -> str:
    """Yerel kısımdaki tüm noktaları kaldır."""

    local_part, sep, domain_part = _split_email(email)
    if not sep:
        return str(email or "").strip()

    main_part, plus_sep, plus_part = _split_local_plus_segment(local_part)
    cleaned_main = main_part.replace(".", "")
    cleaned_local = cleaned_main + (plus_sep + plus_part if plus_sep else "")
    return f"{cleaned_local}{sep}{domain_part}"


def normalize_email_key(email: str) -> str:
    """E-posta adreslerini karşılaştırma için normalize et."""

    lowered = str(email or "").strip().lower()
    if not lowered:
        return ""

    local_part, sep, domain_part = lowered.partition("@")
    if sep != "@" or not domain_part:
        return lowered

    domain_clean = domain_part.strip()
    if not is_gmail_domain(domain_clean):
        return f"{local_part}{sep}{domain_clean}"

    main_part, plus_sep, plus_part = _split_local_plus_segment(local_part)
    normalized_main = main_part.replace(".", "")
    normalized_local = normalized_main + (plus_sep + plus_part if plus_sep else "")
    return f"{normalized_local}{sep}{domain_clean}"
