from dataclasses import dataclass, field
from typing import Dict, Optional

@dataclass
class Outcome:
    text: str
    items_reward: Dict[str, int] = field(default_factory=dict)
    damage_taken: int = 0

@dataclass
class Action:
    id: str
    label: str
    stamina_cost: int
    outcomes: Dict[str, Outcome] = field(default_factory=dict)
    def add_outcome(self, name: str, outcome: Outcome): self.outcomes[name] = outcome

@dataclass
class Interactable:
    id: str
    name: str
    actions: Dict[str, Action] = field(default_factory=dict)
    image_path: Optional[str] = None
    def add_action(self, action: Action): self.actions[action.id] = action
    def get_action(self, action_id: str) -> Optional[Action]: return self.actions.get(action_id)

@dataclass
class Location:
    id: str
    name: str
    description: str
    exits: Dict[str, str] = field(default_factory=dict)
    interactables: Dict[str, Interactable] = field(default_factory=dict) # Key is now the INSTANCE_ID
    image_path: Optional[str] = None
    x: float = 0.0  # X coordinate for map positioning
    y: float = 0.0  # Y coordinate for map positioning
    tags: list = field(default_factory=list)  # Location tags like 'workbench', 'safe_zone', etc.
    npcs: list = field(default_factory=list)  # NPCs at this location
    danger_level: int = 0  # Danger level of the location

    def add_exit(self, direction: str, destination_id: str):
        self.exits[direction] = destination_id

    def add_interactable(self, instance_id: str, interactable_template: Interactable):
        """Adds an instance of an interactable template to the location."""
        self.interactables[instance_id] = interactable_template
        
    def get_interactable(self, instance_id: str) -> Optional[Interactable]:
        return self.interactables.get(instance_id)

class World:
    _instance = None
    def __new__(cls):
        if cls._instance is None:
            cls._instance = super(World, cls).__new__(cls)
            cls._instance.locations = {}
        return cls._instance

    def add_location(self, location: Location): self.locations[location.id] = location
    def get_location(self, location_id: str) -> Optional[Location]: return self.locations.get(location_id)
