"""Estratégias Hypothesis para geração de dados de teste."""

from hypothesis import strategies as st


def webhook_urls_with_tokens() -> st.SearchStrategy[tuple[str, dict[str, str]]]:
    """Gera URLs de webhook com parâmetros `key` e/ou `token` com valores aleatórios.

    Retorna uma tupla (url, sensitive_params) onde:
    - url: URL completa com parâmetros sensíveis e opcionalmente outros parâmetros
    - sensitive_params: dict com os parâmetros sensíveis presentes e seus valores originais
    """
    # Valores para parâmetros sensíveis (não vazios, sem caracteres que quebram URLs)
    param_value = st.text(
        alphabet=st.characters(whitelist_categories=("L", "N"), whitelist_characters="-_"),
        min_size=1,
        max_size=50,
    )

    # Nomes de parâmetros extras (não sensíveis)
    extra_param_name = st.text(
        alphabet=st.characters(whitelist_categories=("L",), whitelist_characters="_"),
        min_size=1,
        max_size=15,
    ).filter(lambda n: n not in ("key", "token"))

    # Parâmetros extras não sensíveis
    extra_params = st.dictionaries(
        keys=extra_param_name,
        values=param_value,
        min_size=0,
        max_size=3,
    )

    # Caminho do espaço
    space_path = st.text(
        alphabet=st.characters(whitelist_categories=("L", "N"), whitelist_characters="-_"),
        min_size=1,
        max_size=30,
    )

    # Quais parâmetros sensíveis incluir (pelo menos um)
    include_key = st.booleans()
    include_token = st.booleans()

    @st.composite
    def build(draw):
        path = draw(space_path)
        has_key = draw(include_key)
        has_token = draw(include_token)

        # Garantir pelo menos um parâmetro sensível
        if not has_key and not has_token:
            has_key = True

        sensitive = {}
        if has_key:
            sensitive["key"] = draw(param_value)
        if has_token:
            sensitive["token"] = draw(param_value)

        extras = draw(extra_params)

        # Construir query string manualmente para controle total
        all_params = {**extras, **sensitive}
        from urllib.parse import urlencode
        query = urlencode(all_params)

        url = f"https://chat.googleapis.com/v1/spaces/{path}/messages?{query}"
        return url, sensitive, extras

    return build()

VALID_WEBHOOK_PREFIX = "https://chat.googleapis.com/"


def valid_webhook_urls() -> st.SearchStrategy[str]:
    """Gera URLs válidas que começam com https://chat.googleapis.com/.

    Produz URLs com caminhos e query strings aleatórios após o prefixo válido.
    """
    suffix = st.text(
        alphabet=st.characters(
            whitelist_categories=("L", "N"),
            whitelist_characters="-_/?.=&",
        ),
        min_size=0,
        max_size=100,
    )
    return suffix.map(lambda s: VALID_WEBHOOK_PREFIX + s)


def invalid_webhook_urls() -> st.SearchStrategy[str]:
    """Gera URLs que NÃO começam com https://chat.googleapis.com/.

    Inclui URLs com outros esquemas, outros domínios, strings arbitrárias,
    e variações próximas do prefixo válido.
    """
    arbitrary_strings = st.text(min_size=0, max_size=200).filter(
        lambda s: not s.startswith(VALID_WEBHOOK_PREFIX)
    )

    other_https_urls = st.text(
        alphabet=st.characters(
            whitelist_categories=("L", "N"),
            whitelist_characters="-_/?.=&:",
        ),
        min_size=1,
        max_size=100,
    ).map(lambda s: "https://example.com/" + s)

    http_urls = st.text(
        alphabet=st.characters(
            whitelist_categories=("L", "N"),
            whitelist_characters="-_/?.=&:",
        ),
        min_size=0,
        max_size=100,
    ).map(lambda s: "http://chat.googleapis.com/" + s)

    return st.one_of(arbitrary_strings, other_https_urls, http_urls)


def valid_texts() -> st.SearchStrategy[str]:
    """Gera strings de texto não vazias para mensagens.

    Produz textos variados incluindo caracteres unicode, espaços e pontuação.
    """
    return st.text(min_size=1, max_size=500)


def valid_titles() -> st.SearchStrategy[str]:
    """Gera strings de título não vazias para cards.

    Produz títulos variados incluindo caracteres unicode, espaços e pontuação.
    """
    return st.text(min_size=1, max_size=200)


def valid_sections() -> st.SearchStrategy[list[dict]]:
    """Gera listas não vazias de dicts com estrutura de seção válida para Card V2.

    Cada seção contém um header opcional e uma lista de widgets com estrutura realista.
    """
    widget_text = st.text(min_size=1, max_size=100)

    text_paragraph_widget = widget_text.map(
        lambda t: {"textParagraph": {"text": t}}
    )

    decorated_text_widget = st.tuples(widget_text, widget_text).map(
        lambda pair: {"decoratedText": {"topLabel": pair[0], "text": pair[1]}}
    )

    widget = st.one_of(text_paragraph_widget, decorated_text_widget)

    section_header = st.one_of(st.none(), st.text(min_size=1, max_size=80))

    @st.composite
    def build_section(draw):
        header = draw(section_header)
        widgets = draw(st.lists(widget, min_size=1, max_size=5))
        section: dict = {"widgets": widgets}
        if header is not None:
            section["header"] = header
        return section

    return st.lists(build_section(), min_size=1, max_size=5)


def card_payloads() -> st.SearchStrategy[tuple[str, list[dict], str | None]]:
    """Gera combinações válidas de title + sections + subtitle opcional para Card V2."""
    return st.tuples(
        valid_titles(),
        valid_sections(),
        st.one_of(st.none(), st.text(min_size=1, max_size=200)),
    )

def valid_thread_keys() -> st.SearchStrategy[str]:
    """Gera strings não vazias para chaves de thread.

    Produz thread keys variadas como 'mr-123', 'deploy-prod-2024', etc.
    """
    return st.text(
        alphabet=st.characters(
            whitelist_categories=("L", "N"),
            whitelist_characters="-_.",
        ),
        min_size=1,
        max_size=100,
    )
