from typing import Optional, Union

import aiohttp
from smb.common.http_client import BaseHttpClientException, collect_errors

from smb.common.aiotvm import HttpClientWithTvm, TvmClient


class GeoproductClientException(BaseHttpClientException):
    pass


class RequestedObjectNotFound(GeoproductClientException):
    pass


class GeoproductClient(HttpClientWithTvm):
    default_uid: int

    def __init__(
        self,
        *,
        url: str,
        default_uid: int,
        tvm_client: TvmClient,
        tvm_source: Optional[Union[str, int]] = None,
        tvm_destination: Union[str, int],
    ):
        super().__init__(
            url=url,
            tvm=tvm_client,
            tvm_source=tvm_source,
            tvm_destination=tvm_destination,
        )
        self.default_uid = default_uid

    @collect_errors
    async def create_order_for_media_platform(
        self, operator_id: int, client_id: int, product_id: int, act_text: str
    ) -> int:
        response = await self.request(
            method="POST",
            uri="/v4/balance-client/geoadv-agency-order",
            headers=self._make_headers(),
            expected_statuses=[200],
            json={
                "operator_id": operator_id,
                "client_id": client_id,
                "product_id": product_id,
                "act_text": act_text,
            },
            metric_name="/v4/balance-client/geoadv-agency-order"
        )
        return response["order_id"]

    @collect_errors
    async def list_reservations(self, permalink: int) -> dict:
        return await self.request(
            method="GET",
            uri="/v3/reservations",
            headers=self._make_headers(),
            params={"permalink": permalink},
            expected_statuses=[200],
            metric_name="/v3/reservations"
        )

    @collect_errors
    async def delete_organization_reservations(self, permalink: int) -> None:
        reservations = await self.list_reservations(permalink)
        for reservation in reservations:
            await self.request(
                method="DELETE",
                uri=f"/v3/reservations/{reservation['id']}",
                headers=self._make_headers(),
                expected_statuses=[200],
                metric_name="/v3/reservations/{reservation['id']}"
            )

    async def _handle_custom_errors(self, response: aiohttp.ClientResponse) -> None:
        if response.status == 404:
            raise RequestedObjectNotFound(await response.json())
        else:
            await self._raise_unknown_response(response)

    def _make_headers(self) -> dict:
        return {"X-Ya-Default-Uid": str(self.default_uid)}
