"""Route402 Python Client"""

import requests
from typing import Optional, List
from datetime import datetime
from eth_account import Account
from web3 import Web3

from .types import Payment, PaymentStatus, Chain, TransactionData
from .exceptions import APIError, PaymentError, ValidationError


class Route402Client:
    """
    Route402 Client for USDC payments on Base blockchain

    Example:
        >>> from route402 import Route402Client
        >>> client = Route402Client(api_key="apk_xxx")
        >>> payment = client.create_payment(
        ...     seller="0x123...",
        ...     amount="0.05",
        ...     chain_id=8453
        ... )
    """

    DEFAULT_API_URL = "https://api.route402.com"
    DEFAULT_TIMEOUT = 30

    def __init__(
        self,
        api_key: str,
        api_url: Optional[str] = None,
        timeout: int = DEFAULT_TIMEOUT
    ):
        """
        Initialize Route402 client

        Args:
            api_key: Your Route402 API key
            api_url: API base URL (default: https://api.route402.com)
            timeout: Request timeout in seconds
        """
        if not api_key:
            raise ValidationError("API key is required")

        self.api_key = api_key
        self.api_url = (api_url or self.DEFAULT_API_URL).rstrip('/')
        self.timeout = timeout
        self.session = requests.Session()
        self.session.headers.update({
            "x-api-key": self.api_key,
            "Content-Type": "application/json",
            "User-Agent": "route402-python/0.1.0"
        })

    def _request(self, method: str, path: str, **kwargs) -> dict:
        """Make HTTP request to API"""
        url = f"{self.api_url}{path}"
        kwargs.setdefault('timeout', self.timeout)

        try:
            response = self.session.request(method, url, **kwargs)
            response.raise_for_status()
            return response.json()
        except requests.exceptions.HTTPError as e:
            try:
                error_data = e.response.json()
                message = error_data.get('error', str(e))
            except:
                message = str(e)
            raise APIError(
                message=message,
                status_code=e.response.status_code,
                response=error_data if 'error_data' in locals() else None
            )
        except requests.exceptions.RequestException as e:
            raise APIError(f"Request failed: {str(e)}")

    def get_chains(self) -> List[dict]:
        """
        Get list of supported chains

        Returns:
            List of chain configurations
        """
        response = self._request('GET', '/router/chains')
        return response.get('chains', [])

    def create_payment(
        self,
        seller: str,
        amount: str,
        chain_id: int = Chain.BASE.value,
        reference: Optional[str] = None
    ) -> Payment:
        """
        Create a new payment

        Args:
            seller: Seller wallet address (0x...)
            amount: Amount in USDC (e.g., "0.05")
            chain_id: Chain ID (default: 8453 for Base)
            reference: Optional reference/order ID

        Returns:
            Payment object

        Example:
            >>> payment = client.create_payment(
            ...     seller="0x123...",
            ...     amount="0.05"
            ... )
        """
        if not Web3.is_address(seller):
            raise ValidationError(f"Invalid seller address: {seller}")

        try:
            float(amount)
        except ValueError:
            raise ValidationError(f"Invalid amount: {amount}")

        data = {
            "seller": seller,
            "amountUSDC": amount,
            "chainId": chain_id
        }
        if reference:
            data["reference"] = reference

        response = self._request('POST', '/pay', json=data)
        return self._parse_payment(response.get('payment'))

    def get_payment(self, payment_id: str) -> Payment:
        """
        Get payment by ID

        Args:
            payment_id: Payment ID

        Returns:
            Payment object
        """
        response = self._request('GET', f'/payments/{payment_id}')
        return self._parse_payment(response.get('payment'))

    def list_payments(
        self,
        limit: int = 50,
        offset: int = 0,
        status: Optional[PaymentStatus] = None
    ) -> List[Payment]:
        """
        List payments for authenticated seller

        Args:
            limit: Number of results (default: 50)
            offset: Pagination offset
            status: Filter by status

        Returns:
            List of Payment objects
        """
        params = {
            "limit": limit,
            "offset": offset
        }
        if status:
            params["status"] = status.value

        response = self._request('GET', '/sellers/me/payments', params=params)
        return [self._parse_payment(p) for p in response.get('payments', [])]

    def export_payments_csv(
        self,
        start_date: Optional[str] = None,
        end_date: Optional[str] = None,
        status: Optional[PaymentStatus] = None
    ) -> str:
        """
        Export payments as CSV

        Args:
            start_date: Start date (YYYY-MM-DD)
            end_date: End date (YYYY-MM-DD)
            status: Filter by status

        Returns:
            CSV content as string
        """
        params = {}
        if start_date:
            params["startDate"] = start_date
        if end_date:
            params["endDate"] = end_date
        if status:
            params["status"] = status.value

        url = f"{self.api_url}/sellers/me/payments/export"
        response = self.session.get(url, params=params, timeout=self.timeout)
        response.raise_for_status()
        return response.text

    def _parse_payment(self, data: dict) -> Payment:
        """Parse payment data from API response"""
        return Payment(
            id=data['id'],
            chain_id=data['chainId'],
            buyer=data['buyer'],
            seller=data['seller'],
            amount=data['amount'],
            fee_bps=data['feeBps'],
            tx_hash=data.get('txHash'),
            status=PaymentStatus(data['status']),
            reference=data.get('reference'),
            created_at=datetime.fromisoformat(data['createdAt'].replace('Z', '+00:00')),
            confirmed_at=datetime.fromisoformat(data['confirmedAt'].replace('Z', '+00:00'))
                if data.get('confirmedAt') else None
        )
