from __future__ import annotations

from typing import Dict, List

import numpy as np

from ..data import Resource
from ..sdk import Action, ActionType, parse_resource

RESOURCE_ORDER: List[Resource] = [
    Resource.BRICK,
    Resource.LUMBER,
    Resource.WOOL,
    Resource.GRAIN,
    Resource.ORE,
]

ACTION_TYPES = list(ActionType)


def encode_observation(obs: Dict[str, object]) -> np.ndarray:
    game = obs["game"]
    current_name = game["current_player"]
    player_info = game["players"][current_name]
    features: List[float] = []

    resources: Dict[Resource, int] = player_info["resources"]
    for resource in RESOURCE_ORDER:
        features.append(float(resources.get(resource, 0)))

    features.extend(
        [
            float(player_info["victory_points"]),
            float(player_info["largest_army"]),
            float(player_info["longest_road"]),
            float(len(player_info["settlements"])),
            float(len(player_info["cities"])),
            float(len(player_info["roads"])),
        ]
    )
    features.append(1.0 if game["phase"] == "main" else 0.0)
    features.append(1.0 if game.get("robber_required") else 0.0)
    features.append(float(len(game.get("pending_discards", []))))
    bank = game.get("bank", {})
    for resource in RESOURCE_ORDER:
        features.append(float(bank.get(resource.value, 0)))
    return np.array(features, dtype=np.float32)


def _resource_vector(value: object) -> List[float]:
    vector = [0.0] * len(RESOURCE_ORDER)
    if value is None:
        return vector
    if isinstance(value, list):
        values = value
    else:
        values = [value]
    for item in values:
        if not item:
            continue
        resource = parse_resource(item) if not isinstance(item, Resource) else item
        if resource == Resource.DESERT:
            continue
        idx = RESOURCE_ORDER.index(resource)
        vector[idx] += 1.0
    return vector


def encode_action(action: Action) -> np.ndarray:
    payload = action.payload or {}
    vector: List[float] = []
    type_vec = [0.0] * len(ACTION_TYPES)
    type_vec[ACTION_TYPES.index(action.type)] = 1.0
    vector.extend(type_vec)

    for key in ("corner", "road", "edge", "hex", "amount"):
        value = float(payload.get(key, 0))
        vector.append(value / 100.0)

    vector.extend(_resource_vector(payload.get("resource")))
    vector.extend(_resource_vector(payload.get("give")))
    vector.extend(_resource_vector(payload.get("receive")))

    return np.array(vector, dtype=np.float32)
