import requests
import hmac
import hashlib
import json
from typing import List, Dict, Any, Optional

class VeyaAPIError(Exception):
    """Exception raised for API errors"""
    pass

class VerificationsClient:
    def __init__(self, api_key: str, base_url: str):
        self._api_key = api_key
        self._base_url = base_url

    def _request(self, method: str, endpoint: str, json: Optional[Dict] = None) -> Dict[str, Any]:
        headers = {
            "Content-Type": "application/json",
            "X-API-Key": self._api_key
        }
        response = requests.request(
            method=method,
            url=f"{self._base_url}{endpoint}",
            headers=headers,
            json=json
        )
        if not response.ok:
            try:
                error_data = response.json()
                msg = error_data.get("error") or error_data.get("message") or "Veya API Error"
            except ValueError:
                msg = f"Veya API Error: {response.status_code} {response.reason}"
            raise VeyaAPIError(msg)
        return response.json()

    def create_link(
        self,
        social: Optional[List[str]] = None,
        data_collection: Optional[List[str]] = None,
        expires_in: int = 3600
    ) -> Dict[str, Any]:
        """
        Create a one-time verification link.
        """
        payload = {
            "requirements": {
                "social": social or [],
                "dataCollection": data_collection or []
            },
            "expires_in": expires_in
        }
        return self._request("POST", "/verifications/link", json=payload)

    def get_result(self, token: str) -> Dict[str, Any]:
        """
        Retrieve the verification result using its token.
        """
        return self._request("GET", f"/verifications/result/{token}")

    def get_transaction(self, verification_id: str) -> Dict[str, Any]:
        """
        Retrieve a verification transaction using its verification_id.
        """
        return self._request("GET", f"/verifications/api/transaction/{verification_id}")

class UsersClient:
    def __init__(self, api_key: str, base_url: str):
        self._api_key = api_key
        self._base_url = base_url

    def _request(self, method: str, endpoint: str, json: Optional[Dict] = None) -> Dict[str, Any]:
        headers = {
            "Content-Type": "application/json",
            "X-API-Key": self._api_key
        }
        response = requests.request(
            method=method,
            url=f"{self._base_url}{endpoint}",
            headers=headers,
            json=json
        )
        if not response.ok:
            try:
                error_data = response.json()
                msg = error_data.get("error") or error_data.get("message") or "Veya API Error"
            except ValueError:
                msg = f"Veya API Error: {response.status_code} {response.reason}"
            raise VeyaAPIError(msg)
        return response.json()

    def search(self, query: str) -> Dict[str, Any]:
        from urllib.parse import quote
        return self._request("GET", f"/verifications/api/search?q={quote(query)}")

    def remove(self, profile_id: str) -> Dict[str, Any]:
        return self._request("DELETE", f"/verifications/api/user/{profile_id}")

    def ban(self, profile_id: str, reason: str = "") -> Dict[str, Any]:
        return self._request("POST", "/verifications/api/ban", json={"profile_id": profile_id, "reason": reason})

    def unban(self, profile_id: str) -> Dict[str, Any]:
        return self._request("DELETE", f"/verifications/api/ban/{profile_id}")

    def list_bans(self) -> Dict[str, Any]:
        return self._request("GET", "/verifications/api/bans")

    def get_bans(self) -> Dict[str, Any]:
        """
        Alias of list_bans for consistency with docs/examples.
        """
        return self._request("GET", "/verifications/api/bans")

class WebhooksClient:
    def __init__(self, webhook_secret: Optional[str] = None):
        self._webhook_secret = webhook_secret

    def verify_signature(self, payload: bytes, signature_header: str, timestamp_header: str, secret: Optional[str] = None) -> Dict[str, Any]:
        """
        Verify the HMAC signature of a webhook payload and return the parsed event.
        """
        webhook_secret = secret or self._webhook_secret
        if not webhook_secret:
            raise ValueError("Webhook secret is required to verify signatures. Pass it in the Veya constructor or method call.")
            
        if not signature_header or not signature_header.startswith("v1="):
            raise ValueError("Missing or invalid signature format")
            
        if not timestamp_header:
            raise ValueError("Missing timestamp header")
            
        signature = signature_header[3:]
        
        data_to_sign = timestamp_header.encode('utf-8') + b"." + payload
        
        expected_signature = hmac.new(
            webhook_secret.encode('utf-8'),
            data_to_sign,
            hashlib.sha256
        ).hexdigest()
        
        if not hmac.compare_digest(signature, expected_signature):
            raise ValueError("Invalid signature")
            
        return json.loads(payload)

class Veya:
    def __init__(self, api_key: str, base_url: str = "https://veya.kr/api/v1", webhook_secret: Optional[str] = None):
        if not api_key:
            raise ValueError("Veya API Key is required")
        self.api_key = api_key
        self.base_url = base_url
        self.webhook_secret = webhook_secret

        self.verifications = VerificationsClient(api_key, base_url)
        self.users = UsersClient(api_key, base_url)
        self.webhooks = WebhooksClient(webhook_secret)
