import httpx

from typing import Optional, List, Any

from ..utils import get_params
from ..interfaces import Core, Dto
from ..collection import Collection
from ..providers import RequestService
from ..interfaces.mongo import Filter, Query


class RestfulService[T: Core, D: Dto](RequestService):
  def __init__(self, path: Collection, client: httpx.Client, path_prefix: str = "/") -> None:
    self.path, self.path_prefix = path, path_prefix
    super().__init__(client=client)

  def url(self, path: Optional[str] = None, prefix: Optional[str] = None) -> str:
    prefix = self.path_prefix if prefix is None else prefix
    return f"{prefix or '/'}{self.path}{f'/{path}' if path else ''}"

  def count(self, query: Query, brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any) -> Any:
    params = get_params(config=config, brotli_cfg=brotli, query_or_filter=query)
    response = super().get(self.url("count"), **{**config, "params": params})
    return response if full_response else response["total"]

  def create(self, data: D, brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any) -> Any:
    params = get_params(config=config, brotli_cfg=brotli)
    response = super().post(self.url(), data=data, **{**config, "params": params})
    return response if full_response else response["data"]

  def create_bulk(self, data: List[D], brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any) -> Any:
    params = get_params(config=config, brotli_cfg=brotli)
    response = super().post(self.url("bulk"), data=data, **{**config, "params": params})
    return response if full_response else response["items"]

  def find(self, filter: Filter, brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any) -> Any:
    params = get_params(config=config, brotli_cfg=brotli, query_or_filter=filter)
    response = super().get(self.url(), **{**config, "params": params})
    return response if full_response else response["items"]

  def find_by_id(self, id: str, brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any) -> Any:
    params = get_params(config=config, brotli_cfg=brotli)
    response = super().get(self.url(id), **{**config, "params": params})
    return response if full_response else response["data"]

  def delete_by_id(self, id: str, brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any) -> Any:
    params = get_params(config=config, brotli_cfg=brotli)
    response = super().delete(self.url(id), **{**config, "params": params})
    return response if full_response else response["data"]

  def restore_by_id(self, id: str, brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any) -> Any:
    params = get_params(config=config, brotli_cfg=brotli)
    response = super().put(self.url(f"{id}/restore"), data=None, **{**config, "params": params})
    return response if full_response else response["data"]

  def destroy_by_id(self, id: str, brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any) -> Any:
    params = get_params(config=config, brotli_cfg=brotli)
    response = super().delete(self.url(f"{id}/destroy"), **{**config, "params": params})
    return response if full_response else response["data"]

  def update_bulk(
    self, data: Optional[D], query: Query, brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any
  ) -> Any:
    params = get_params(config=config, brotli_cfg=brotli, query_or_filter=query)
    response = super().patch(self.url("bulk"), data=data, **{**config, "params": params})
    return response if full_response else response["total"]

  def update_by_id(
    self, id: str, data: Optional[D], brotli: Optional[Any] = None, full_response: Optional[bool] = None, **config: Any
  ) -> Any:
    params = get_params(config=config, brotli_cfg=brotli)
    response = super().patch(self.url(id), data=data, **{**config, "params": params})
    return response if full_response else response["data"]
