import logging
from abc import ABC, abstractmethod
from datetime import date

from pydantic import BaseModel

from wbportfolio.order_routing.model import ExecutionStatus, Order


class AdapterOrder(BaseModel):
    @classmethod
    def from_order(cls, order: Order) -> "AdapterOrder":
        raise NotImplementedError()

    def to_order(self) -> Order:
        raise NotImplementedError()


class BaseCustodianAdapter(ABC):
    order_model: AdapterOrder

    def __init__(self, isin: str, rebalance_date: date, ticker: str | None = None, logger=None, **execution_kwarg):
        self.isin = isin
        self.rebalance_date = rebalance_date
        self.ticker = ticker
        self.execution_kwarg = execution_kwarg
        self.logger = logger if logger else logging.getLogger(__name__)

    @property
    def errors(self):
        if not hasattr(self, "_errors"):
            raise ValueError("is_valid needs to call before accessing errors")
        return

    @abstractmethod
    def authenticate(self) -> bool:
        """
        Authenticate or renew tokens with the custodian API.
        Raises an exception if authentication fails.
        """
        pass

    @abstractmethod
    def is_valid(self) -> bool:
        """
        Check whether the given isin is valid and can be rebalanced
        """
        pass

    @abstractmethod
    def get_rebalance_status(self) -> tuple[ExecutionStatus, str]:
        """
        Return the rebalance status as a string (in the custodian format)
        """
        pass

    @abstractmethod
    def submit_rebalancing(self, items: list[dict[str, str]], as_draft: bool = True) -> tuple[list[dict], str, dict]:
        """
        Submit a rebalance order for the certificate.
        """
        pass

    @abstractmethod
    def cancel_current_rebalancing(self) -> bool:
        """
        Cancel an existing rebalance order identified by ISIN.
        """
        pass

    @abstractmethod
    def get_current_rebalancing(self) -> list[dict[str, str]]:
        """
        Fetch the current rebalance request details for a certificate.
        """
        pass

    def serialize_order(self, order: Order) -> dict:
        return self.order_model.from_order(order).model_dump(mode="json")

    def deserialize_item(self, item) -> Order:
        return self.order_model.model_validate(item).to_order()
