from django.conf import settings
from requests import HTTPError

from wbportfolio.api_clients.ubs import UBSNeoAPIClient
from wbportfolio.order_routing.adapters.base import BaseCustodianAdapter
from wbportfolio.order_routing.adapters.ubs.model import UBSOrder
from wbportfolio.order_routing.exception import RoutingError
from wbportfolio.order_routing.model import ExecutionStatus

STATUS_MAP = {
    "Amend Pending": ExecutionStatus.PENDING,
    "Cancel Pending": ExecutionStatus.PENDING,
    "Cancelled": ExecutionStatus.CANCELLED,
    "Complete": ExecutionStatus.COMPLETED,
    "Complete (Order Cancelled)": ExecutionStatus.COMPLETED,
    "Complete (Partial Fill)": ExecutionStatus.COMPLETED,
    "In Draft": ExecutionStatus.IN_DRAFT,
    "Pending Approval": ExecutionStatus.PENDING,
    "Pending Execution": ExecutionStatus.PENDING,
    "Rebalance Cancelled": ExecutionStatus.CANCELLED,
    "Rebalance Cancelled (Executing partially)": ExecutionStatus.CANCELLED,
    "Rejected": ExecutionStatus.REJECTED,
    "Rejection Acknowledged": ExecutionStatus.PENDING,
    "Waiting for Response": ExecutionStatus.PENDING,
}


class CustodianAdapter(BaseCustodianAdapter):
    client: UBSNeoAPIClient
    order_model = UBSOrder

    def __init__(self, *args, raise_exception: bool = False, **kwargs):
        super().__init__(*args, **kwargs)
        self.raise_exception = raise_exception

    def _handle_response(self, res):
        self.logger.info(res["message"])
        if errors := res.get("errors"):
            self.logger.warning(errors)
            if self.raise_exception:
                raise RoutingError(errors)

    def authenticate(self) -> bool:
        """
        Authenticate or renew tokens with the custodian API.
        Raises an exception if authentication fails.
        """
        self.client = UBSNeoAPIClient(settings.UBS_NEO_API_TOKEN)
        return True

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

        try:
            status_res = self.client.get_rebalance_service_status()

            isin_res = self.client.get_rebalance_status_for_isin(self.isin)
            self._handle_response(status_res)
            self._handle_response(isin_res)
            return (
                status_res["status"] == UBSNeoAPIClient.SUCCESS_VALUE
                and isin_res["status"] == UBSNeoAPIClient.SUCCESS_VALUE
            )
        except (HTTPError, KeyError) as e:
            self.logger.warning(f"Couldn't validate adapter: {str(e)}")
            return False

    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.
        """
        if not as_draft:
            res = self.client.submit_rebalance(self.isin, items)
        else:
            res = self.client.save_draft(self.isin, items)
        self._handle_response(res)

        return res["rebalanceItems"], res["message"], {}

    def cancel_current_rebalancing(self) -> bool:
        """
        Cancel an existing rebalance order identified by ISIN.
        """
        try:
            res = self.client.cancel_rebalance(self.isin)
            self._handle_response(res)
            return res["status"] == UBSNeoAPIClient.SUCCESS_VALUE
        except (HTTPError, KeyError):
            return False

    def get_rebalance_status(self) -> tuple[ExecutionStatus, str]:
        res = self.client.get_rebalance_status_for_isin(self.isin)
        self._handle_response(res)
        status = res.get("rebalanceStatus", "")
        return STATUS_MAP.get(status, ExecutionStatus.UNKNOWN), status

    def get_current_rebalancing(self) -> list[dict[str, str]]:
        """
        Fetch the current rebalance request details for a certificate.
        """
        res = self.client.get_current_rebalance_request(self.isin)
        self._handle_response(res)
        return res["rebalanceItems"]
