import aiohttp
import logging

logger = logging.getLogger(__name__)

async def zarinpal_request(merchant_id: str, amount_tomans: int, description: str, callback_url: str, sandbox: bool = True) -> str | None:
    # Zarinpal uses Rials in v4 API
    amount_rials = amount_tomans * 10
    url = "https://sandbox.zarinpal.com/pg/v4/payment/request.json" if sandbox else "https://api.zarinpal.com/pg/v4/payment/request.json"
    
    payload = {
        "merchant_id": merchant_id,
        "amount": amount_rials,
        "description": description,
        "callback_url": callback_url,
        "metadata": {"mobile": "", "email": ""}
    }
    
    try:
        async with aiohttp.ClientSession() as session:
            async with session.post(url, json=payload, headers={"Content-Type": "application/json"}) as resp:
                data = await resp.json()
                if data and "data" in data and data["data"] and "authority" in data["data"]:
                    return data["data"]["authority"]
                else:
                    logger.error(f"Zarinpal request error: {data}")
    except Exception as e:
        logger.error(f"Zarinpal request exception: {e}")
    return None

async def zarinpal_verify(merchant_id: str, amount_tomans: int, authority: str, sandbox: bool = True) -> tuple[bool, str]:
    amount_rials = amount_tomans * 10
    url = "https://sandbox.zarinpal.com/pg/v4/payment/verify.json" if sandbox else "https://api.zarinpal.com/pg/v4/payment/verify.json"
    
    payload = {
        "merchant_id": merchant_id,
        "amount": amount_rials,
        "authority": authority
    }
    
    try:
        async with aiohttp.ClientSession() as session:
            async with session.post(url, json=payload, headers={"Content-Type": "application/json"}) as resp:
                data = await resp.json()
                if data and "data" in data and data["data"] and data["data"].get("code") in [100, 101]:
                    ref_id = data["data"].get("ref_id", "0")
                    return True, str(ref_id)
                else:
                    errors = data.get("errors")
                    logger.error(f"Zarinpal verify error: {data}")
                    return False, str(errors or "پرداخت ناموفق")
    except Exception as e:
        logger.error(f"Zarinpal verify exception: {e}")
        return False, str(e)

async def zibal_request(merchant_id: str, amount_tomans: int, callback_url: str, description: str) -> str | None:
    # Zibal uses Tomans
    url = "https://gateway.zibal.ir/v1/request"
    
    payload = {
        "merchant": merchant_id,
        "amount": amount_tomans,
        "callbackUrl": callback_url,
        "description": description
    }
    
    try:
        async with aiohttp.ClientSession() as session:
            async with session.post(url, json=payload, headers={"Content-Type": "application/json"}) as resp:
                data = await resp.json()
                if data and data.get("result") == 100:
                    return str(data.get("trackId"))
                else:
                    logger.error(f"Zibal request error: {data}")
    except Exception as e:
        logger.error(f"Zibal request exception: {e}")
    return None

async def zibal_verify(merchant_id: str, track_id: int | str) -> tuple[bool, str]:
    url = "https://gateway.zibal.ir/v1/verify"
    
    payload = {
        "merchant": merchant_id,
        "trackId": int(track_id)
    }
    
    try:
        async with aiohttp.ClientSession() as session:
            async with session.post(url, json=payload, headers={"Content-Type": "application/json"}) as resp:
                data = await resp.json()
                if data and data.get("result") in [100, 101]:
                    ref_num = data.get("refNumber", "0")
                    return True, str(ref_num)
                else:
                    logger.error(f"Zibal verify error: {data}")
                    message = data.get("message", "تایید ناموفق")
                    return False, message
    except Exception as e:
        logger.error(f"Zibal verify exception: {e}")
        return False, str(e)
