package com.openosrs.client.core.bridge;

import com.openosrs.client.api.types.*;
import com.openosrs.client.core.ClientCore;
import net.runelite.api.*;
import net.runelite.api.coords.WorldPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * RuneLiteBridge - Bridges the modern agent API with the legacy RuneLite API.
 * 
 * This class provides conversion methods between our modernized data structures
 * and the original RuneLite API structures, allowing us to leverage existing
 * RuneLite functionality while providing a clean agent-friendly interface.
 */
public class RuneLiteBridge {
    private static final Logger logger = LoggerFactory.getLogger(RuneLiteBridge.class);
    
    private final ClientCore clientCore;
    private Client runeliteClient; // Will be injected when available
    
    public RuneLiteBridge(ClientCore clientCore) {
        this.clientCore = clientCore;
        
        // Automatically try to connect to RuneLite client
        initializeConnection();
    }
    
    /**
     * Initialize connection to RuneLite client.
     */
    private void initializeConnection() {
        ClientConnector.connectToRuneLiteClient()
            .thenAccept(client -> {
                if (client != null) {
                    setRuneLiteClient(client);
                } else {
                    logger.warn("No RuneLite client found - bridge will operate in standalone mode");
                }
            })
            .exceptionally(throwable -> {
                logger.error("Error connecting to RuneLite client", throwable);
                return null;
            });
    }
    
    /**
     * Set the RuneLite client instance.
     */
    public void setRuneLiteClient(Client client) {
        this.runeliteClient = client;
        logger.info("RuneLite client bridge established");
    }
    
    /**
     * Check if the bridge is active (RuneLite client is available).
     */
    public boolean isActive() {
        return runeliteClient != null;
    }
    
    // === POSITION CONVERSIONS ===
    
    /**
     * Convert RuneLite WorldPoint to our Position.
     */
    public Position toPosition(WorldPoint worldPoint) {
        if (worldPoint == null) {
            return null;
        }
        return new Position(worldPoint.getX(), worldPoint.getY(), worldPoint.getPlane());
    }
    
    /**
     * Convert our Position to RuneLite WorldPoint.
     */
    public WorldPoint toWorldPoint(Position position) {
        if (position == null) {
            return null;
        }
        return new WorldPoint(position.getX(), position.getY(), position.getPlane());
    }
    
    // === PLAYER CONVERSIONS ===
    
    /**
     * Get the player's current position from RuneLite.
     */
    @Nullable
    public Position getPlayerPosition() {
        if (!isActive()) {
            return null;
        }
        
        Player localPlayer = runeliteClient.getLocalPlayer();
        if (localPlayer == null) {
            return null;
        }
        
        WorldPoint worldPoint = localPlayer.getWorldLocation();
        return toPosition(worldPoint);
    }
    
    /**
     * Get player skill information from RuneLite.
     */
    public int getSkillLevel(Skill skill) {
        if (!isActive()) {
            return 1;
        }
        
        return runeliteClient.getBoostedSkillLevel(convertSkill(skill));
    }
    
    /**
     * Get real (base) skill level from RuneLite.
     */
    public int getSkillRealLevel(Skill skill) {
        if (!isActive()) {
            return 1;
        }
        
        return runeliteClient.getRealSkillLevel(convertSkill(skill));
    }
    
    /**
     * Get skill experience from RuneLite.
     */
    public int getSkillExperience(Skill skill) {
        if (!isActive()) {
            return 0;
        }
        
        return runeliteClient.getSkillExperience(convertSkill(skill));
    }
    
    /**
     * Convert our Skill enum to RuneLite Skill enum.
     */
    private net.runelite.api.Skill convertSkill(Skill agentSkill) {
        // Map our skill enum to RuneLite's skill enum
        switch (agentSkill) {
            case ATTACK: return net.runelite.api.Skill.ATTACK;
            case DEFENCE: return net.runelite.api.Skill.DEFENCE;
            case STRENGTH: return net.runelite.api.Skill.STRENGTH;
            case HITPOINTS: return net.runelite.api.Skill.HITPOINTS;
            case RANGED: return net.runelite.api.Skill.RANGED;
            case PRAYER: return net.runelite.api.Skill.PRAYER;
            case MAGIC: return net.runelite.api.Skill.MAGIC;
            case COOKING: return net.runelite.api.Skill.COOKING;
            case WOODCUTTING: return net.runelite.api.Skill.WOODCUTTING;
            case FLETCHING: return net.runelite.api.Skill.FLETCHING;
            case FISHING: return net.runelite.api.Skill.FISHING;
            case FIREMAKING: return net.runelite.api.Skill.FIREMAKING;
            case CRAFTING: return net.runelite.api.Skill.CRAFTING;
            case SMITHING: return net.runelite.api.Skill.SMITHING;
            case MINING: return net.runelite.api.Skill.MINING;
            case HERBLORE: return net.runelite.api.Skill.HERBLORE;
            case AGILITY: return net.runelite.api.Skill.AGILITY;
            case THIEVING: return net.runelite.api.Skill.THIEVING;
            case SLAYER: return net.runelite.api.Skill.SLAYER;
            case FARMING: return net.runelite.api.Skill.FARMING;
            case RUNECRAFT: return net.runelite.api.Skill.RUNECRAFT;
            case HUNTER: return net.runelite.api.Skill.HUNTER;
            case CONSTRUCTION: return net.runelite.api.Skill.CONSTRUCTION;
            default: return net.runelite.api.Skill.ATTACK;
        }
    }
    
    // === NPC CONVERSIONS ===
    
    /**
     * Convert RuneLite NPC to our NPC.
     */
    public NPC toNPC(net.runelite.api.NPC runeliteNPC) {
        if (runeliteNPC == null) {
            return null;
        }
        
        Position position = toPosition(runeliteNPC.getWorldLocation());
        String name = runeliteNPC.getName();
        int id = runeliteNPC.getId();
        int index = runeliteNPC.getIndex();
        
        // Get NPC composition for additional info
        NPCComposition composition = runeliteNPC.getComposition();
        int combatLevel = 0;
        if (composition != null) {
            combatLevel = composition.getCombatLevel();
        }
        
        // Get animation
        int animationId = runeliteNPC.getAnimation();
        
        // Check combat state (simplified)
        boolean inCombat = runeliteNPC.getHealthRatio() < 100;
        
        // Get overhead text
        String overheadText = runeliteNPC.getOverheadText();
        
        return new NPC(
            index, id, name, position,
            -1, -1, // HP not directly available
            combatLevel, animationId, inCombat,
            overheadText
        );
    }
    
    /**
     * Get all NPCs from RuneLite.
     */
    public List<NPC> getAllNPCs() {
        if (!isActive()) {
            return new ArrayList<>();
        }
        
        List<net.runelite.api.NPC> runeliteNPCs = runeliteClient.getNpcs();
        return runeliteNPCs.stream()
                .map(this::toNPC)
                .filter(npc -> npc != null)
                .collect(Collectors.toList());
    }
    
    // === GAME OBJECT CONVERSIONS ===
    
    /**
     * Convert RuneLite GameObject to our GameObject.
     */
    public GameObject toGameObject(net.runelite.api.GameObject runeliteObject) {
        if (runeliteObject == null) {
            return null;
        }
        
        Position position = toPosition(runeliteObject.getWorldLocation());
        int id = runeliteObject.getId();
        
        // Get object composition for additional info
        ObjectComposition composition = runeliteClient.getObjectDefinition(id);
        String name = "Unknown";
        String[] actions = new String[0];
        
        if (composition != null) {
            name = composition.getName();
            actions = composition.getActions();
        }
        
        return new GameObject(
            id, name, position,
            runeliteObject.getHash(), // Use hash as type
            0, // Orientation not directly available
            actions
        );
    }
    
    /**
     * Get all game objects from RuneLite scene.
     */
    public List<GameObject> getAllGameObjects() {
        if (!isActive()) {
            return new ArrayList<>();
        }
        
        List<GameObject> objects = new ArrayList<>();
        
        Scene scene = runeliteClient.getScene();
        if (scene == null) {
            return objects;
        }
        
        Tile[][][] tiles = scene.getTiles();
        int plane = runeliteClient.getPlane();
        
        for (int x = 0; x < tiles[plane].length; x++) {
            for (int y = 0; y < tiles[plane][x].length; y++) {
                Tile tile = tiles[plane][x][y];
                if (tile != null) {
                    // Get wall objects
                    WallObject wallObject = tile.getWallObject();
                    if (wallObject != null) {
                        GameObject gameObj = toGameObject(wallObject);
                        if (gameObj != null) {
                            objects.add(gameObj);
                        }
                    }
                    
                    // Get decorative objects
                    DecorativeObject decorativeObject = tile.getDecorativeObject();
                    if (decorativeObject != null) {
                        GameObject gameObj = toGameObject(decorativeObject);
                        if (gameObj != null) {
                            objects.add(gameObj);
                        }
                    }
                    
                    // Get ground objects
                    GroundObject groundObject = tile.getGroundObject();
                    if (groundObject != null) {
                        GameObject gameObj = toGameObject(groundObject);
                        if (gameObj != null) {
                            objects.add(gameObj);
                        }
                    }
                    
                    // Get game objects
                    net.runelite.api.GameObject[] gameObjects = tile.getGameObjects();
                    if (gameObjects != null) {
                        for (net.runelite.api.GameObject gameObject : gameObjects) {
                            if (gameObject != null) {
                                GameObject gameObj = toGameObject(gameObject);
                                if (gameObj != null) {
                                    objects.add(gameObj);
                                }
                            }
                        }
                    }
                }
            }
        }
        
        return objects;
    }
    
    // === GROUND ITEM CONVERSIONS ===
    
    /**
     * Convert RuneLite TileItem to our GroundItem.
     */
    public GroundItem toGroundItem(TileItem tileItem, Position position) {
        if (tileItem == null) {
            return null;
        }
        
        int itemId = tileItem.getId();
        int quantity = tileItem.getQuantity();
        
        // Get item composition for name
        ItemComposition composition = runeliteClient.getItemDefinition(itemId);
        String name = "Unknown";
        boolean tradeable = true; // Default assumption
        
        if (composition != null) {
            name = composition.getName();
            tradeable = composition.isTradeable();
        }
        
        return new GroundItem(
            itemId, name, quantity, position,
            System.currentTimeMillis(), // Use current time as spawn time
            tradeable
        );
    }
    
    /**
     * Get all ground items from RuneLite scene.
     */
    public List<GroundItem> getAllGroundItems() {
        if (!isActive()) {
            return new ArrayList<>();
        }
        
        List<GroundItem> groundItems = new ArrayList<>();
        
        Scene scene = runeliteClient.getScene();
        if (scene == null) {
            return groundItems;
        }
        
        Tile[][][] tiles = scene.getTiles();
        int plane = runeliteClient.getPlane();
        
        for (int x = 0; x < tiles[plane].length; x++) {
            for (int y = 0; y < tiles[plane][x].length; y++) {
                Tile tile = tiles[plane][x][y];
                if (tile != null) {
                    ItemLayer itemLayer = tile.getItemLayer();
                    if (itemLayer != null) {
                        // Get the tile's world position
                        WorldPoint worldPoint = WorldPoint.fromScene(runeliteClient, x, y, plane);
                        Position position = toPosition(worldPoint);
                        
                        // Get the bottom item
                        TileItem bottom = itemLayer.getBottom();
                        if (bottom != null) {
                            GroundItem groundItem = toGroundItem(bottom, position);
                            if (groundItem != null) {
                                groundItems.add(groundItem);
                            }
                        }
                        
                        // Get the top item
                        TileItem top = itemLayer.getTop();
                        if (top != null && top != bottom) {
                            GroundItem groundItem = toGroundItem(top, position);
                            if (groundItem != null) {
                                groundItems.add(groundItem);
                            }
                        }
                        
                        // Get middle items
                        TileItem middle = itemLayer.getMiddle();
                        if (middle != null && middle != bottom && middle != top) {
                            GroundItem groundItem = toGroundItem(middle, position);
                            if (groundItem != null) {
                                groundItems.add(groundItem);
                            }
                        }
                    }
                }
            }
        }
        
        return groundItems;
    }
    
    // === INVENTORY CONVERSIONS ===
    
    /**
     * Convert RuneLite Item to our Item.
     */
    public Item toItem(net.runelite.api.Item runeliteItem) {
        if (runeliteItem == null) {
            return Item.EMPTY;
        }
        
        int itemId = runeliteItem.getId();
        int quantity = runeliteItem.getQuantity();
        
        if (itemId == -1 || quantity == 0) {
            return Item.EMPTY;
        }
        
        // Get item composition for additional info
        ItemComposition composition = runeliteClient.getItemDefinition(itemId);
        String name = "Unknown";
        boolean stackable = false;
        boolean tradeable = true;
        String[] actions = new String[0];
        
        if (composition != null) {
            name = composition.getName();
            stackable = composition.isStackable();
            tradeable = composition.isTradeable();
            actions = composition.getInventoryActions();
        }
        
        return new Item(
            itemId, name, quantity, stackable, tradeable, actions
        );
    }
    
    /**
     * Get inventory from RuneLite.
     */
    public Item[] getInventory() {
        if (!isActive()) {
            return new Item[28];
        }
        
        ItemContainer inventory = runeliteClient.getItemContainer(InventoryID.INVENTORY);
        if (inventory == null) {
            return new Item[28];
        }
        
        net.runelite.api.Item[] runeliteItems = inventory.getItems();
        Item[] agentItems = new Item[28];
        
        for (int i = 0; i < 28; i++) {
            if (i < runeliteItems.length) {
                agentItems[i] = toItem(runeliteItems[i]);
            } else {
                agentItems[i] = Item.EMPTY;
            }
        }
        
        return agentItems;
    }
    
    /**
     * Get equipment from RuneLite.
     */
    public Item[] getEquipment() {
        if (!isActive()) {
            return new Item[14];
        }
        
        ItemContainer equipment = runeliteClient.getItemContainer(InventoryID.EQUIPMENT);
        if (equipment == null) {
            return new Item[14];
        }
        
        net.runelite.api.Item[] runeliteItems = equipment.getItems();
        Item[] agentItems = new Item[14];
        
        for (int i = 0; i < 14; i++) {
            if (i < runeliteItems.length) {
                agentItems[i] = toItem(runeliteItems[i]);
            } else {
                agentItems[i] = Item.EMPTY;
            }
        }
        
        return agentItems;
    }
    
    // === PLAYER STATE ===
    
    /**
     * Get player's run energy.
     */
    public int getRunEnergy() {
        if (!isActive()) {
            return 100;
        }
        
        return runeliteClient.getEnergy();
    }
    
    /**
     * Get player's current animation.
     */
    public int getCurrentAnimation() {
        if (!isActive()) {
            return -1;
        }
        
        Player localPlayer = runeliteClient.getLocalPlayer();
        if (localPlayer == null) {
            return -1;
        }
        
        return localPlayer.getAnimation();
    }
    
    /**
     * Get player's username.
     */
    public String getUsername() {
        if (!isActive()) {
            return "Unknown";
        }
        
        Player localPlayer = runeliteClient.getLocalPlayer();
        if (localPlayer == null) {
            return "Unknown";
        }
        
        return localPlayer.getName();
    }
    
    /**
     * Check if player is moving.
     */
    public boolean isMoving() {
        if (!isActive()) {
            return false;
        }
        
        Player localPlayer = runeliteClient.getLocalPlayer();
        if (localPlayer == null) {
            return false;
        }
        
        return localPlayer.getPoseAnimation() != localPlayer.getIdlePoseAnimation();
    }
    
    /**
     * Get the game state.
     */
    public int getGameState() {
        if (!isActive()) {
            return 0;
        }
        
        GameState state = runeliteClient.getGameState();
        if (state == null) {
            return 0;
        }
        
        // Convert RuneLite game state to our constants
        switch (state) {
            case STARTING: return ClientCore.GameStateConstants.STARTUP;
            case LOGIN_SCREEN: return ClientCore.GameStateConstants.INITIALIZED;
            case LOGGING_IN: return ClientCore.GameStateConstants.CONNECTING;
            case LOGGED_IN: return ClientCore.GameStateConstants.LOGGED_IN;
            case LOADING: return ClientCore.GameStateConstants.CONNECTING;
            case HOPPING: return ClientCore.GameStateConstants.CONNECTING;
            case CONNECTION_LOST: return ClientCore.GameStateConstants.DISCONNECTED;
            case UNKNOWN: return ClientCore.GameStateConstants.ERROR;
            default: return ClientCore.GameStateConstants.IN_GAME;
        }
    }
}