import uuid
from dotenv import load_dotenv
import os
import aiohttp
import json
from payments.pay_provider import BasePayProvider, Invoice
from pydantic import BaseModel, UUID4, Field
from typing import Optional
from decimal import Decimal
import logging

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

SBP_P2P = 1
SBP_QR = 2

class PaymentDetails(BaseModel):
    amount: int
    currency: str = "RUB"


class PaymentPayload(BaseModel):
    order_id: str


class PaymentRequest(BaseModel):
    paymentMethod: int = Field(description="Payment method")
    id: UUID4 = Field(description="Transaction ID in UUID format")
    paymentDetails: PaymentDetails
    description: str = Field(description="Payment purpose")
    return_url: str = Field(description="Redirect URL for successful payment", alias="return")
    FailedUrl: str = Field(default="https://google.com", description="Redirect URL for failed payment")

    class Config:
        populate_by_name = True


load_dotenv()

PLATEGA_API_KEY = os.getenv("PLATEGA_API_KEY")
PLATEGA_MERCHANT_KEY= os.getenv("PLATEGA_MERCHANT_KEY")


class PayProvider(BasePayProvider):
    def __init__(self, bot_username: str):
        self.api_key = PLATEGA_API_KEY
        self.merchant_key = PLATEGA_MERCHANT_KEY
        self.api_url = "https://app.platega.io"
        self.bot_username = bot_username
        self.name = "💳 СБП"
        self.callback_data_prefix = "platega"
        self.min_amount = 50
        self.description = "<i>Для осуществления оплаты предоставляется срок в 15 минут.</i>"

    async def _make_request(self, method: str, endpoint: str, params: dict = None):
        headers = {
            "X-Secret": self.api_key,
            "X-MerchantId": self.merchant_key,
            "Content-Type": "application/json"
        }
        async with aiohttp.ClientSession() as session:
            url = f"{self.api_url}/{endpoint}"
            if method == "GET":
                async with session.get(url, params=params, headers=headers) as response:
                    status = response.status
                    try:
                        data = await response.json()
                        return status, data
                    except:
                        text = await response.text()
                        return status, text
            elif method == "POST":
                async with session.post(url, json=params, headers=headers) as response:
                    status = response.status
                    try:
                        data = await response.json()
                        return status, data
                    except:
                        text = await response.text()
                        return status, text
    
    async def is_available(self) -> bool:
        return self.api_key is not None and self.merchant_key is not None
    
    async def create_invoice(self, amount: int, payment_id: str, description: str) -> Invoice:
        if amount < self.min_amount:
            raise Exception(f"Минимальная сумма оплаты для {self.name} - 50 руб.")
        for _ in range(3):  # Try up to 3 times
            try:
                # Ensure description is not empty
                if not description:
                    description = "Оплата услуг VPN"
                
                payment_request = PaymentRequest(
                    paymentMethod=SBP_QR,
                    id=str(uuid.uuid4()),  # Convert UUID to string immediately
                    paymentDetails=PaymentDetails(amount=int(amount)),
                    description=description,
                    return_url=f"https://t.me/{self.bot_username}",
                    FailedUrl=f"https://t.me/{self.bot_username}"
                )

                # Сериализуем в JSON и обратно в dict для гарантии правильной сериализации
                request_data = json.loads(payment_request.model_dump_json(by_alias=True))
                logger.info("Request data: %s", json.dumps(request_data, indent=2))
                
                status, response_data = await self._make_request("POST", "transaction/process", request_data)
                logger.info("Response data: %s", json.dumps(response_data, indent=2))
                
                if status == 200:
                    # Get nspk link
                    nspk_link = await self.get_nspk_link(response_data["transactionId"])
                    return Invoice(response_data["transactionId"], amount, nspk_link)
                elif status == 400:
                    if isinstance(response_data, dict) and "message" in response_data and "Transaction " in response_data["message"]:
                        logger.info("Transaction already exists: %s", response_data['message'])
                        continue  # Try again with a new UUID
                    else:
                        message = response_data.get("message", str(response_data)) if isinstance(response_data, dict) else str(response_data)
                        logger.info("API error: %s", message)
                        continue  # Try again with a new UUID
                else:
                    logger.info("Unexpected status code: %s", status)
                    continue  # Try again with a new UUID
                    
            except Exception as e:
                logger.info("Error in create_invoice: %s", e)
                continue  # Try again with a new UUID
                
        # If we get here, all attempts failed
        raise Exception("Failed to create invoice after multiple attempts")
    
    async def get_nspk_link(self, invoice_id: str) -> str:
        url = f"h2h/{invoice_id}"
        status, response_data = await self._make_request("GET", url)
        logger.info("Response data: %s", json.dumps(response_data, indent=2))
        if status == 200 and isinstance(response_data, dict):
            return response_data.get("qr")
        return None

    async def check_invoice(self, invoice_id: str, payment_id: str) -> bool:
        try:
            status, response_data = await self._make_request("GET", f"transaction/{invoice_id}")
            if status == 200 and isinstance(response_data, dict):
                return response_data.get("status") == "CONFIRMED"
            return False
        except Exception as e:
            logger.info("Error checking invoice: %s", e)
            return False
