import asyncio
import json
import shutil
import urllib.parse
from database import get_setting

_TIMEOUT = 25
_UA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/122.0.0.0 Safari/537.36'
_MARK = '\n__HTTPSTATUS__:'


class ApiResult:
    def __init__(self, ok, data=None, error=None, status_code=None):
        self.ok = ok
        self.data = data
        self.error = error
        self.status_code = status_code


async def _curl_post(url: str, form: dict):
    """درخواست POST از طریق پروسه‌ی curl (نه httpx/urllib).
    برخی هاست‌ها روی اثر انگشت TLS (JA3/JA4) کتابخانه‌های شبکه‌ی پایتون (ssl module) فیلتر می‌کنند
    و کانکشن را قطع/Timeout می‌کنند، در حالی که همان درخواست از طریق curl (که TLS استک متفاوتی
    دارد) بدون مشکل پاسخ می‌گیرد. چون در Termux/لینوکس curl معمولاً از قبل نصب است، از آن به‌عنوان
    زیرفرآیند استفاده می‌کنیم تا رفتار واقعی مرورگر/curl را دقیقاً بازتولید کنیم.
    خروجی: (status_code یا None، raw_body)"""
    body = urllib.parse.urlencode(form)
    args = [
        'curl', '-sS', '--max-time', str(_TIMEOUT),
        '-A', _UA,
        '-H', 'Accept: application/json, text/plain, */*',
        '-d', body,
        '-w', _MARK + '%{http_code}',
        url,
    ]
    proc = await asyncio.create_subprocess_exec(
        *args, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE,
    )
    try:
        stdout, stderr = await asyncio.wait_for(proc.communicate(), timeout=_TIMEOUT + 5)
    except asyncio.TimeoutError:
        try:
            proc.kill()
        except ProcessLookupError:
            pass
        raise RuntimeError('اجرای curl بیش از حد طول کشید (killed).')

    out = stdout.decode('utf-8', errors='replace')
    if proc.returncode != 0:
        err = stderr.decode('utf-8', errors='replace').strip()
        raise RuntimeError(f'curl با کد خروج {proc.returncode} شکست خورد: {err or "بدون جزئیات"}')

    if _MARK not in out:
        return None, out
    raw_body, _, status_str = out.rpartition(_MARK)
    try:
        status = int(status_str.strip())
    except ValueError:
        status = None
    return status, raw_body


class ProviderApiClient:
    async def post(self, payload):
        url = get_setting('api_url').strip()
        key = get_setting('api_key').strip()
        if not url or not key:
            return ApiResult(False, error='API URL یا API Key در پنل تنظیم نشده است.')
        if not shutil.which('curl'):
            return ApiResult(False, error='ابزار curl روی این سیستم نصب نیست. نصب کنید: pkg install curl (Termux) یا apt install curl.')

        form = {'key': key, **payload}
        last = 'خطای ناشناخته'
        for attempt in range(3):
            try:
                status, raw = await _curl_post(url, form)

                try:
                    data = json.loads(raw) if raw else None
                except ValueError:
                    data = None

                if data is None:
                    snippet = (raw or '')[:200].replace('\n', ' ').strip() or '(پاسخ خالی)'
                    last = f'پاسخ سرور JSON معتبر نیست (کد HTTP {status}): {snippet}'
                    if attempt < 2:
                        await asyncio.sleep(1.5 ** (attempt + 1)); continue
                    return ApiResult(False, error=last, status_code=status)

                if status is not None and status >= 400:
                    last = f'خطای HTTP {status}: {data if isinstance(data, dict) else str(data)[:200]}'
                    if attempt < 2:
                        await asyncio.sleep(1.5 ** (attempt + 1)); continue
                    return ApiResult(False, error=last, status_code=status)

                if isinstance(data, dict) and data.get('error'):
                    return ApiResult(False, data=data, error=str(data['error']), status_code=status)

                return ApiResult(True, data=data, status_code=status)

            except Exception as e:
                last = f'خطای اتصال به سرور ({type(e).__name__}): {e or "بدون جزئیات"}'
                if attempt < 2:
                    await asyncio.sleep(1.5 ** (attempt + 1))
        return ApiResult(False, error=last)

    async def services(self):
        return await self.post({'action': 'services'})

    async def balance(self):
        return await self.post({'action': 'balance'})

    async def status(self, order):
        return await self.post({'action': 'status', 'order': order})

    async def add(self, service, link, quantity, **extra):
        return await self.post({'action': 'add', 'service': service, 'link': link, 'quantity': quantity, **extra})


provider_api = ProviderApiClient()
