"""HTTP client wrapping the Go API server."""

import httpx


class CorpoClient:
    """Synchronous HTTP client for the corpo Go API."""

    def __init__(self, base_url: str, timeout: float = 30.0, api_key: str = ""):
        self.base_url = base_url.rstrip("/")
        headers = {}
        if api_key:
            headers["Authorization"] = f"Bearer {api_key}"
        self._client = httpx.Client(base_url=self.base_url, timeout=timeout, headers=headers)

    def close(self):
        self._client.close()

    # --- Read endpoints ---

    def get_realm(self, address: str) -> dict:
        return self._get(f"/api/v1/realm/{address}")

    def get_realm_by_name(self, name: str) -> dict:
        return self._get(f"/api/v1/realm/by-name/{name}")

    def list_realms(self) -> list:
        return self._get("/api/v1/realms")

    def get_governance(self, address: str) -> dict:
        return self._get(f"/api/v1/governance/{address}")

    def list_governances(self, realm: str) -> list:
        return self._get("/api/v1/governances", params={"realm": realm})

    def get_proposal(self, address: str) -> dict:
        return self._get(f"/api/v1/proposal/{address}")

    def list_proposals(self, governance: str) -> list:
        return self._get("/api/v1/proposals", params={"governance": governance})

    def get_member(self, realm: str, mint: str, owner: str) -> dict:
        return self._get(f"/api/v1/member/{realm}/{mint}/{owner}")

    def list_members(self, realm: str) -> list:
        return self._get("/api/v1/members", params={"realm": realm})

    def get_treasury(self, governance: str) -> dict:
        return self._get(f"/api/v1/treasury/{governance}")

    # --- Account endpoints ---

    def register_account(self, email: str) -> dict:
        return self._post("/api/v1/accounts", {"email": email})

    def get_account(self, account_id: str) -> dict:
        return self._get(f"/api/v1/accounts/{account_id}")

    # --- Transaction endpoints ---

    def tx_create_realm(self, data: dict) -> dict:
        return self._post("/api/v1/tx/create-realm", data)

    def tx_deposit_tokens(self, data: dict) -> dict:
        return self._post("/api/v1/tx/deposit-tokens", data)

    def tx_withdraw_tokens(self, data: dict) -> dict:
        return self._post("/api/v1/tx/withdraw-tokens", data)

    def tx_create_governance(self, data: dict) -> dict:
        return self._post("/api/v1/tx/create-governance", data)

    def tx_create_proposal(self, data: dict) -> dict:
        return self._post("/api/v1/tx/create-proposal", data)

    def tx_cast_vote(self, data: dict) -> dict:
        return self._post("/api/v1/tx/cast-vote", data)

    def tx_cancel_proposal(self, data: dict) -> dict:
        return self._post("/api/v1/tx/cancel-proposal", data)

    def tx_sign_off_proposal(self, data: dict) -> dict:
        return self._post("/api/v1/tx/sign-off-proposal", data)

    def tx_add_signatory(self, data: dict) -> dict:
        return self._post("/api/v1/tx/add-signatory", data)

    def tx_finalize_vote(self, data: dict) -> dict:
        return self._post("/api/v1/tx/finalize-vote", data)

    def tx_relinquish_vote(self, data: dict) -> dict:
        return self._post("/api/v1/tx/relinquish-vote", data)

    def tx_execute_transaction(self, data: dict) -> dict:
        return self._post("/api/v1/tx/execute-transaction", data)

    def tx_set_governance_delegate(self, data: dict) -> dict:
        return self._post("/api/v1/tx/set-governance-delegate", data)

    def tx_create_token_owner_record(self, data: dict) -> dict:
        return self._post("/api/v1/tx/create-token-owner-record", data)

    def tx_create_native_treasury(self, data: dict) -> dict:
        return self._post("/api/v1/tx/create-native-treasury", data)

    # --- Quote endpoints ---

    def create_quote(self, entity_name: str, entity_type: str = "dao_llc", wallet_address: str = "") -> dict:
        body: dict = {"entity_name": entity_name, "entity_type": entity_type}
        if wallet_address:
            body["wallet_address"] = wallet_address
        return self._post("/api/v1/quotes", body)

    def get_quote(self, quote_id: str) -> dict:
        return self._get(f"/api/v1/quotes/{quote_id}")

    def pay_quote(self, quote_id: str, method: str = "credit_card") -> dict:
        return self._post(f"/api/v1/quotes/{quote_id}/pay", {"method": method})

    # --- Corporate Actions endpoints ---

    def get_actions_catalog(self) -> list:
        return self._get("/api/v1/actions/catalog")

    def list_available_actions(self, entity_id: str) -> list:
        return self._get(f"/api/v1/entities/{entity_id}/actions/available")

    def list_actions(self, entity_id: str) -> list:
        return self._get(f"/api/v1/entities/{entity_id}/actions")

    def initiate_action(self, entity_id: str, action_type: str, params: dict | None = None) -> dict:
        body: dict = {"action_type": action_type}
        if params:
            body["params"] = params
        return self._post(f"/api/v1/entities/{entity_id}/actions", body)

    def get_action(self, entity_id: str, action_id: str) -> dict:
        return self._get(f"/api/v1/entities/{entity_id}/actions/{action_id}")

    def get_action_forms(self, entity_id: str, action_id: str) -> list:
        return self._get(f"/api/v1/entities/{entity_id}/actions/{action_id}/forms")

    def execute_action(self, entity_id: str, action_id: str) -> dict:
        return self._post(f"/api/v1/entities/{entity_id}/actions/{action_id}/execute", {})

    # --- Recipe endpoints ---

    def list_recipes(self) -> list:
        return self._get("/api/v1/recipes")

    def get_recipe(self, recipe_id: str) -> dict:
        return self._get(f"/api/v1/recipes/{recipe_id}")

    def execute_recipe(self, entity_id: str, recipe_id: str, step_params: dict | None = None) -> dict:
        body: dict = {}
        if step_params:
            body["step_params"] = step_params
        return self._post(f"/api/v1/entities/{entity_id}/recipes/{recipe_id}/execute", body)

    def setup_governance(self, entity_id: str, realm_address: str, governance_program_id: str) -> dict:
        return self._put(f"/api/v1/entities/{entity_id}/governance", {
            "realm_address": realm_address,
            "governance_program_id": governance_program_id,
        })

    def update_action_status(self, entity_id: str, action_id: str, status: str) -> dict:
        return self._put(f"/api/v1/entities/{entity_id}/actions/{action_id}", {"status": status})

    # --- Internal helpers ---

    def _get(self, path: str, params: dict | None = None) -> dict | list:
        resp = self._client.get(path, params=params)
        resp.raise_for_status()
        return resp.json()

    def _put(self, path: str, data: dict) -> dict:
        resp = self._client.put(path, json=data)
        if resp.status_code >= 400:
            body = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
            raise CorpoAPIError(resp.status_code, body.get("error", resp.text))
        return resp.json()

    def _post(self, path: str, data: dict) -> dict:
        resp = self._client.post(path, json=data)
        if resp.status_code >= 400:
            body = resp.json() if resp.headers.get("content-type", "").startswith("application/json") else {}
            raise CorpoAPIError(resp.status_code, body.get("error", resp.text))
        return resp.json()


class CorpoAPIError(Exception):
    """Error from the corpo Go API."""

    def __init__(self, status_code: int, message: str):
        self.status_code = status_code
        self.message = message
        super().__init__(f"API error {status_code}: {message}")
