from __future__ import annotations

import copy
import logging
from typing import List, Dict, Any

import safe_radix32
from clarabot_nano_common.common.config.extract.effective_api import EffectiveApiExtractedConfig

logger = logging.getLogger(__name__)


class ServesExtractedConfig(EffectiveApiExtractedConfig):
    """
    Collect an inverse map of the rooms the system's resources shall be bound to. (the rooms this Nano wishes to serve)
    NOTE: Resources that are not mapped to a single valid room are filtered out!
    """

    def __init__(self, config):
        EffectiveApiExtractedConfig.__init__(self, config)
        self.deny_anonymous: bool = config["remote"]["deny_anonymous"]
        self.require_explicit_peer_trust: bool = config["remote"]["require_explicit_peer_trust"]
        self.rooms: Dict[int, Dict[int, dict]] = dict()  # room-id -> {api_flag: resource}
        self._init_room_serves(self.effective_drive_api, config["remote"]["drives"])

    def _init_room_serves(self, api_flag: int, resources: List[dict]):
        resources = copy.deepcopy(resources)
        for resource in resources:
            for packed_room_id in resource.pop("rooms", []):
                try:
                    room_id = safe_radix32.decode(packed_room_id)
                except (UnicodeEncodeError, OverflowError):
                    logger.warning("Ignoring invalid room-id: %s", packed_room_id)
                    continue
                room_apis = self.rooms.get(room_id)
                if not room_apis:
                    self.rooms[room_id] = {api_flag: resource}
                elif api_flag not in room_apis:
                    room_apis[api_flag] = resource

    def get_serves(self) -> List[Dict[str, Any]]:
        serves = []
        for room_id, room_apis in self.rooms.items():
            api = 0
            for api_flag in room_apis.keys():
                api |= api_flag
            if api:
                serves.append({"id": room_id, "api": api})
        return serves

    def _matches(self, other: ServesExtractedConfig) -> bool:
        return (
            EffectiveApiExtractedConfig._matches(self, other)
            and self.rooms == other.rooms
            and self.deny_anonymous == other.deny_anonymous
            and self.require_explicit_peer_trust == other.require_explicit_peer_trust
        )
