from __future__ import annotations

import time
from typing import Any, Dict, Mapping, Optional, Union

import requests


def POST_直到成功(
    url: str,
    data: Optional[Union[Mapping[str, Any], bytes, str]] = None,
    json: Optional[Any] = None,
    headers: Optional[Dict[str, str]] = None,
    cookies: Optional[Dict[str, str]] = None,
    timeout: Union[int, float] = 10,
    allow_redirects: bool = True,
    verify: bool = True,
    proxies: Optional[Dict[str, str]] = None,
    重试间隔秒: Union[int, float] = 3,
    最大尝试次数: Optional[int] = None,
) -> Optional[requests.Response]:
    """
    发送 HTTP POST 请求并返回响应对象（requests.Response），支持失败自动重试。

    本函数面向“工具库 / 爬虫 / 自动化”场景设计，强调稳定与可控：
        - 成功返回 requests.Response
        - 请求失败（异常 / 非 2xx）时按间隔重试
        - 达到最大尝试次数仍失败时返回 None
        - 函数内部不抛出异常
        - 本函数为完全独立实现，不调用其他 HTTP 工具函数

    发送内容说明：
        - 优先使用 json 参数（requests 会自动序列化为 JSON，并设置合适的 Content-Type）
        - 否则使用 data 参数（常用于表单、原始文本或 bytes）

    成功判定规则：
        - HTTP 状态码在 200 ~ 299 范围内视为成功

    Args:
        url (str): 目标 URL，例如 "https://example.com/api".
        data (Optional[Union[Mapping[str, Any], bytes, str]]):
            请求体内容（非 JSON 场景）。
            - Mapping/dict：按表单方式提交（x-www-form-urlencoded；若未来你传 files 则会走 multipart）
            - str/bytes：原样作为请求体发送
        json (Optional[Any]):
            JSON 请求体。可以是 dict/list 等可 JSON 序列化对象。
            注意：当 json 不为 None 时，将优先使用 json。
        headers (Optional[Dict[str, str]]): 请求头字典，例如 {"User-Agent": "..."}。
        cookies (Optional[Dict[str, str]]): Cookie 字典。
        timeout (Union[int, float]): 单次请求超时时间（秒），例如 10 或 3.5。
        allow_redirects (bool): 是否允许自动跟随重定向。
        verify (bool): 是否验证 HTTPS 证书。为 False 时可能降低安全性。
        proxies (Optional[Dict[str, str]]): 代理配置，例如：
            {"http": "http://127.0.0.1:7890", "https": "http://127.0.0.1:7890"}。
        重试间隔秒 (Union[int, float]): 每次失败后的等待时间（秒），默认 3 秒。
        最大尝试次数 (Optional[int]):
            - None：无限重试（默认）
            - int：最多尝试指定次数，超过后返回 None

    Returns:
        Optional[requests.Response]:
            - 成功：返回响应对象（requests.Response）
            - 失败：返回 None
    """
    if not isinstance(url, str) or not url.strip():
        return None

    次数 = 0

    while True:
        try:
            if json is not None:
                响应 = requests.post(
                    url=url,
                    json=json,
                    headers=headers,
                    cookies=cookies,
                    timeout=timeout,
                    allow_redirects=allow_redirects,
                    verify=verify,
                    proxies=proxies,
                )
            else:
                响应 = requests.post(
                    url=url,
                    data=data,
                    headers=headers,
                    cookies=cookies,
                    timeout=timeout,
                    allow_redirects=allow_redirects,
                    verify=verify,
                    proxies=proxies,
                )

            状态码 = getattr(响应, "status_code", None)
            if isinstance(状态码, int) and 200 <= 状态码 < 300:
                return 响应

        except Exception:
            pass

        次数 += 1
        if 最大尝试次数 is not None and 次数 >= 最大尝试次数:
            return None

        time.sleep(重试间隔秒)