package org.project;

import org.project.entity.players.*;
import org.project.entity.enemies.*;
import org.project.location.Location;
import org.project.item.armors.*;
import org.project.item.weapons.*;
import org.project.item.Item;
import org.project.item.consumables.Flask;
import org.project.item.consumables.StaminaPotion;

import java.util.*;

public class Main {

    private static final String RESET = "\033[0m";     // Text Reset

    private static final String GREEN = "\033[0;32m";  // HP / Healing
    private static final String BLUE = "\033[0;34m";   // Stamina
    private static final String RED = "\033[0;31m";    // Enemies
    private static final String YELLOW = "\033[0;33m"; // Coins / XP
    private static final String PURPLE = "\033[0;35m"; // Events
    private static final String CYAN = "\033[0;36m";   // Locations


    public static void main(String[] args) {

        Scanner scanner = new Scanner(System.in);
        Random random = new Random();


        ArrayList<Enemy> forestEnemies = new ArrayList<>();
        Location forest = new Location("The Dark Forest", forestEnemies);

        ArrayList<Enemy> graveyardEnemies = new ArrayList<>();
        Location graveyard = new Location("The Forsaken Graveyard", graveyardEnemies);

        ArrayList<Enemy> cryptEnemies = new ArrayList<>();
        Location crypt = new Location("The Blood Crypt", cryptEnemies);

        Location[] standardLocations = {forest, graveyard, crypt};

        Enemy dragon = new Dragon(new Flame("Flame", 60, 10));



        System.out.println("\n" + PURPLE + "=== WELCOME TO THE GRIM REALM ===" + RESET);
        System.out.println("Choose Your Character:");
        System.out.println("1. Knight | 2. Assassin | 3. Wizard");
        String choice = scanner.nextLine();

        System.out.print("Enter Your Hero's Name: ");
        String name = scanner.nextLine();

        Player player = null;
        switch (choice) {
            case "1":
                player = new Knight(name, new Sword("Sword", 40, 5), new KnightArmor("Knight Plate", 30));
                break;
            case "2":
                player = new Assassin(name, new HiddenBlade("Hidden Blade", 30, 5), new AssassinArmor("Assassin Plate", 30));
                break;
            case "3":
                player = new Wizard(name, new Staff("Staff", 20, 5), new WizardArmor("Wizard Plate", 30));
                break;
            default:
                System.out.println("Invalid Choice.");
        }


        boolean playing = true;
        String currentState = "CAMP";
        while (playing && player.isAlive()) {

            switch (currentState) {
                case "CAMP":
                    player.fillStats();
                    System.out.println("\n" + CYAN + "=== CAMP ===" + RESET);
                    System.out.println("HP: " + GREEN + player.getHP() + "/" + player.getMaxHP() + RESET + " | " +
                            "Stamina: " + BLUE + player.getStamina() + "/" + player.getMaxStamina() + RESET);
                    System.out.println("Level: " + player.getLevel() + " | Coins: " + YELLOW + player.getCoins() + RESET + "\n");
                    System.out.println("1. Step Into The Portal");
                    System.out.println("2. Visit The Merchant");
                    System.out.println("3. Rest By The Fire (Quit Game)");

                    String hubChoice = scanner.nextLine();

                    switch (hubChoice) {
                        case "1":
                            System.out.println("\n" + PURPLE + "The Portal Swirls." + RESET + " Where To?");
                            System.out.println("1. Hunt The Dragon's Minions (Random Location)");
                            System.out.println("2. Challenge The Dragon (The Castle)");
                            String portalChoice = scanner.nextLine();

                            switch (portalChoice) {
                                case "1":
                                    currentState = "RANDOM";
                                    break;
                                case "2":
                                    currentState = "CASTLE";
                                    break;
                                default:
                                    System.out.println("Invalid Choice.");
                            }
                            break;
                        case "2":
                            visitMerchant(player, scanner);
                            break;
                        case "3":
                            System.out.println(PURPLE + "You Rest By The Fire. Game Saved." + RESET);
                            playing = false;
                            break;
                        default:
                            System.out.println("Invalid Choice.");
                    }
                    break;

                case "RANDOM":
                    Location currentLoc = standardLocations[random.nextInt(standardLocations.length)];
                    Enemy areaEnemy = null;

                    if (currentLoc.getName().contains("Forest")) {
                        areaEnemy = new Goblin(new Dagger("Dagger", 20, 5));
                    } else if (currentLoc.getName().contains("Graveyard")) {
                        areaEnemy = new Skeleton(new Sword("Dagger", 20, 5));
                    } else if (currentLoc.getName().contains("Crypt")) {
                        areaEnemy = new Vampire(new Sword("Dagger", 20, 5));
                    }

                    System.out.println("\n" + PURPLE + "You Get Out Of The Portal..." + RESET);
                    System.out.println("You Find Yourself In " + CYAN + currentLoc.getName() + RESET + ".");
                    System.out.println("A " + RED + areaEnemy.getName() + RESET + " Is Lurking In The Shadows!");

                    System.out.println("\nWhat Will You Do?");
                    System.out.println("1. Fight The " + areaEnemy.getName());
                    System.out.println("2. Step Back Into The Portal (Teleport Elsewhere)");

                    String portalChoice = scanner.nextLine();

                    switch (portalChoice) {
                        case "1":
                            battle(player, areaEnemy, scanner);
                            if (!player.isAlive()) {
                                break;
                            }
                            System.out.println("\nWhat Will You Do Now?");
                            System.out.println("1. Continue Hunting The Enemies");
                            System.out.println("2. Get Back To Camp To Recover");
                            String victoryChoice = scanner.nextLine();

                            switch (victoryChoice) {
                                case "1":
                                    currentState = "RANDOM";
                                    break;
                                case "2":
                                    currentState = "CAMP";
                                    break;
                                default:
                                    System.out.println("Invalid Choice.");
                            }
                            break;
                        case "2":
                            System.out.println("\n" + PURPLE + "The Portal Swirls." + RESET + " Where To?");
                            System.out.println("1. Hunt The Dragon's Minions (Random Location)");
                            System.out.println("2. Return To The Camp");
                            String portalChoice1 = scanner.nextLine();

                            switch (portalChoice1) {
                                case "1":
                                    currentState = "RANDOM";
                                    break;
                                case "2":
                                    currentState = "CAMP";
                                    break;
                                default:
                                    System.out.println("Invalid Choice.");
                            }
                            break;
                        default:
                            System.out.println("Invalid Choice.");
                    }
                    break;

                case "CASTLE":
                    System.out.println("\nYou Stand Before The Massive Gates Of The Castle.");

                    if (player.getInventory().hasAllKeys()) {
                        System.out.println("The Three Keys React To The Dark Magic." + PURPLE + " The Gate Opens!" + RESET);
                        player.setCanDefend(false);
                        battle(player, dragon, scanner);
                        player.setCanDefend(true);
                        playing = false;
                    } else {
                        System.out.println("You Must Have All 3 Keys To Open The Gates.");
                        System.out.println("\n" + PURPLE + "The Portal Behind You Swirls." + RESET + " Where To?");
                        System.out.println("1. Hunt The Dragon's Minions (Find The Missing Keys)");
                        System.out.println("2. Return To Camp");

                        String castleChoice = scanner.nextLine();
                        switch (castleChoice) {
                            case "1":
                                currentState = "RANDOM";
                                break;
                            case "2":
                                currentState = "CAMP";
                                break;
                            default:
                                System.out.println("Invalid Choice.");
                        }
                    }
                    break;
            }
        }
    }


    private static void battle(Player player, Enemy enemy, Scanner scanner) {
        System.out.println("\n" + ">>>" + PURPLE + " BATTLE STARTED: " + GREEN + player.getName() + RESET + " VS " + RED + enemy.getName() + RESET + " <<<");

        boolean isPlayerTurn = true;

        while (player.isAlive() && enemy.isAlive()) {
            if (isPlayerTurn) {
                boolean actionTaken = false;

                while (!actionTaken && player.isAlive()) {
                    if(!player.isStunned()) {
                        System.out.println("\n--- YOUR TURN ---");
                        System.out.println("HP: " + GREEN + player.getHP() + RESET + " | Stamina: " + BLUE + player.getStamina()  + RESET +
                                " |" + PURPLE + "VS" + RESET + "| " +
                                "Enemy HP: " + RED + enemy.getHP() + RESET + " | " + "Enemy Stamina: " + BLUE + enemy.getStamina() + RESET);

                        System.out.println("1. Light Attack (" + BLUE + "0" + RESET + ") | " +
                                "2. Heavy Attack (" + BLUE + player.getWeapon().getStaminaCost() + RESET + ") | " +
                                "3. Defend (" + BLUE + "5" + RESET + ") | " +
                                "4. Special (" + BLUE + "20" + RESET + ") | " +
                                "5. " + YELLOW + "Use Healing Potion" + RESET + " (" + BLUE + "0" + RESET + ") | " +
                                "6. " + YELLOW + "Use Stamina Potion" + RESET + " (" + BLUE + "0" + RESET + ")");
                        // Removed Healing By Using Stamina Since It Didn't Really Make Sense.

                        String choice = scanner.nextLine();

                        switch (choice) {
                            case "1":
                                player.lightAttack(enemy);
                                actionTaken = true;
                                break;
                            case "2":
                                player.heavyAttack(enemy);
                                actionTaken = true;
                                break;
                            case "3":
                                player.defend();
                                actionTaken = true;
                                break;
                            case "4":
                                player.specialAbility(enemy);
                                actionTaken = true;
                                break;
                            case "5":
                                Item healingFlask = player.getInventory().getMiscItemByName("Healing Flask");

                                if (healingFlask == null || healingFlask.getQuantity() <= 0) {
                                    System.out.println("You Don't Have Any Healing Flasks Left!");
                                    break;
                                }

                                healingFlask.use(player);
                                break;
                            case "6":
                                Item staminaPotion = player.getInventory().getMiscItemByName("Stamina");

                                if (staminaPotion == null || staminaPotion.getQuantity() <= 0) {
                                    System.out.println("You Don't Have Any Stamina Potions Left!");
                                    break;
                                }

                                staminaPotion.use(player);
                                break;

                            default: System.out.println("Invalid Selection.");
                        }
                    } else {
                        System.out.println("\n" + PURPLE + "You Are Stunned And Skip Your Turn!" + RESET);
                        actionTaken = true;
                        player.setStunned(false);

                    }
                }
                isPlayerTurn = false;
            } else {

                if (!enemy.isStunned()) {
                    System.out.println("\n--- ENEMY TURN ---");
                    int enemyMove = enemy.choice();
                    System.out.println(enemyMove);
                    switch (enemyMove) {
                        case 1:
                            enemy.lightAttack(player);
                            break;
                        case 2:
                            enemy.heavyAttack(player);
                            break;
                        case 3:
                            enemy.defend();
                            break;
                        case 4: // Dragon's Special Ability Which Stuns The Player
                            player.takeDamage(80, enemy);
                            player.setStunned(true);
                            System.out.println("The Dragon Has Stunned You!");
                            break;
                    }
                } else {
                    System.out.println("\n" + PURPLE + "The Enemy Is Stunned And Skips Their Turn!" + RESET);
                    enemy.setStunned(false);
                }
                isPlayerTurn = true;
            }
        }

        if (!enemy.isAlive()) {
            handleVictory(player, enemy);
        } else if (!player.isAlive()) {
            System.out.println(RED + "\nYOU DIED." + RESET + " Your Soul Remains In The Grim Realm...");
        }
    }


    private static void handleVictory(Player player, Enemy enemy) {
        System.out.println("\n" + GREEN + "--- VICTORY! ---" + RESET);
        player.addCoins(enemy.getCoinReward());

        if (!(enemy instanceof Dragon)) {
            if (enemy.hasKey()) {
                if (enemy instanceof Goblin && !player.hasGoblinKey()) {
                    player.findGoblinKey();
                } else if (enemy instanceof Skeleton && !player.hasSkeletonKey()) {
                    player.findSkeletonKey();
                } else if (enemy instanceof Vampire && !player.hasVampireKey()) {
                    player.findVampireKey();
                }
            } else {
                System.out.println("The Enemy Had No Keys With Him.");
            }
            player.gainXP(enemy.getXpReward());
        } else {
            player.gainXP(enemy.getXpReward());
            System.out.println(PURPLE + "THE DRAGON DESCENDS!" + RESET);
        }
    }


    private static void visitMerchant(Player player, Scanner scanner) {
        boolean inShop = true;

        ArrayList<Weapon> weaponsForSale = new ArrayList<>();
        ArrayList<Integer> weaponPrice = new ArrayList<>();
        ArrayList<Armor> armorsForSale = new ArrayList<>();
        ArrayList<Integer> armorPrice = new ArrayList<>();

        // You Can Add Multiple Armors And Weapons Here
        if (player instanceof Knight) {
            weaponsForSale.add(new Sword("GreatSword", 50, 0));
            weaponPrice.add(100);
            armorsForSale.add(new KnightArmor("Templar Plate", 70));
            armorPrice.add(200);
        } else if (player instanceof Assassin) {
            weaponsForSale.add(new HiddenBlade("Dual Hidden Blades", 40, 0));
            weaponPrice.add(100);
            armorsForSale.add(new KnightArmor("Master Assassin Plate", 70));
            armorPrice.add(200);
        } else if (player instanceof Wizard) {
            weaponsForSale.add(new Staff("GreatStaff", 30, 0));
            weaponPrice.add(100);
            armorsForSale.add(new KnightArmor("Magician Plate", 70));
            armorPrice.add(200);
        }



        Item healingPotion = new Flask(3);
        int healingPotionPrice = 20;

        Item staminaPotion = new StaminaPotion(3);
        int staminaPotionPrice = 10;

        System.out.println("\nWelcome, Stranger!");

        while (inShop) {
            System.out.println("\n" + CYAN + "=== MERCHANT SHOP ===" + RESET);
            System.out.println("1. View and Buy Equipment");
            System.out.println("2. Manage Equipment");
            System.out.println("0. Exit Shop");

            String choice = scanner.nextLine();

            switch (choice) {
                case "1":
                    boolean viewingWares = true;
                    while (viewingWares) {
                        System.out.println("\n" + PURPLE + "=== FOR SALE ===" + RESET);
                        System.out.println("Your Coins: " + YELLOW + player.getCoins() + RESET);

                        System.out.println("1. Weapons");
                        System.out.println("2. Armors");
                        System.out.println("3. " + healingPotion.getName() + " (" + healingPotion.getQuantity() + ") " + " - " + YELLOW + healingPotionPrice + RESET + " Coins");
                        System.out.println("4. " + staminaPotion.getName() + " (" + healingPotion.getQuantity() + ") " + " - " + YELLOW + staminaPotionPrice + RESET + " Coins");
                        System.out.println("0. Back To Main Shop Menu");

                        System.out.println("\nEnter Item Number:");
                        String buyChoice = scanner.nextLine();

                        switch (buyChoice) {
                            case "1":
                                boolean buyingWeapons = true;
                                while (buyingWeapons) {
                                    for (int i = 0; i < weaponsForSale.size(); i++) {
                                        System.out.println((i + 1) + ". " + weaponsForSale.get(i).getName() + " (Damage: " + weaponsForSale.get(i).getDamage() + ")" + " - " + YELLOW + weaponPrice.get(i) + " Coins" + RESET);
                                    }
                                    System.out.println("0. Back To Buy Menu");
                                    String weaponChoice = scanner.nextLine();
                                    try {
                                        int weaponIdx = Integer.parseInt(weaponChoice) - 1;


                                        if (weaponIdx == -1) {
                                            buyingWeapons = false;
                                        } else if (weaponIdx >= 0 && weaponIdx < weaponsForSale.size()) {
                                            Weapon selectedWeapon = weaponsForSale.get(weaponIdx);
                                            int price = weaponPrice.get(weaponIdx);

                                            if (player.getCoins() >= price) {
                                                player.spendCoins(price);
                                                player.getInventory().addWeapon(selectedWeapon);
                                                System.out.println(GREEN + "Bought " + selectedWeapon.getName() + "!" + RESET);

                                                weaponsForSale.remove(weaponIdx);
                                                weaponPrice.remove(weaponIdx);


                                            } else {
                                                System.out.println(RED + "Not Enough Coins!" + RESET);
                                            }
                                        } else if (weaponIdx != -1) {
                                            System.out.println("Invalid Weapon Selection.");
                                        }
                                    } catch (NumberFormatException e) {
                                        System.out.println("Invalid Selection.");
                                    }
                                }

                                break;
                            case "2":
                                boolean buyingArmors = true;
                                while (buyingArmors) {
                                    for (int i = 0; i < armorsForSale.size(); i++) {
                                        System.out.println((i + 1) + ". " + armorsForSale.get(i).getName() + " (Defense: " + armorsForSale.get(i).getDefense() + ")" + " - " + YELLOW + armorPrice.get(i) + " Coins" + RESET);
                                    }
                                    System.out.println("0. Back To Buy Menu");
                                    String armorChoice = scanner.nextLine();
                                    try {
                                        int armorIdx = Integer.parseInt(armorChoice) - 1;


                                        if (armorIdx == -1) {
                                            buyingArmors = false;
                                        } else if (armorIdx >= 0 && armorIdx < armorsForSale.size()) {
                                            Armor selectedArmor = armorsForSale.get(armorIdx);
                                            int price = armorPrice.get(armorIdx);

                                            if (player.getCoins() >= price) {
                                                player.spendCoins(price);
                                                player.getInventory().addArmor(selectedArmor);
                                                System.out.println(GREEN + "Bought " + selectedArmor.getName() + "!" + RESET);

                                                armorsForSale.remove(armorIdx);
                                                armorPrice.remove(armorIdx);


                                            } else {
                                                System.out.println(RED + "Not Enough Coins!" + RESET);
                                            }
                                        } else if (armorIdx != -1) {
                                            System.out.println("Invalid Armor Selection.");
                                        }
                                    } catch (NumberFormatException e) {
                                        System.out.println("Invalid Selection.");
                                    }
                                }
                                break;
                            case "3":
                                if (player.getCoins() >= healingPotionPrice) {
                                    player.spendCoins(healingPotionPrice);
                                    player.getInventory().addMiscItem(healingPotion);
                                    System.out.println(GREEN + "Bought " + healingPotion.getName() + "!" + RESET);
                                } else {
                                    System.out.println(RED + "Not Enough Coins!" + RESET);
                                }
                                break;
                            case "4":
                                if (player.getCoins() >= staminaPotionPrice) {
                                    player.spendCoins(staminaPotionPrice);
                                    player.getInventory().addMiscItem(staminaPotion);
                                    System.out.println(GREEN + "Bought " + staminaPotion.getName() + "!" + RESET);
                                } else {
                                    System.out.println(RED + "Not Enough Coins!" + RESET);
                                }
                                break;
                            case "0":
                                viewingWares = false;
                                break;
                            default:
                                System.out.println("Invalid Selection.");
                        }
                    }
                    break;

                case "2":
                    boolean managing = true;
                    while (managing) {
                        System.out.println("\n" + PURPLE + "=== MANAGE EQUIPMENT ===" + RESET);
                        System.out.println("1. Weapons");
                        System.out.println("2. Armors");
                        System.out.println("3. View Inventory");
                        System.out.println("0. Back To Main Shop Menu");

                        String manageChoice = scanner.nextLine();

                        switch (manageChoice) {
                            case "1":
                                boolean choosingWeapon = true;
                                while (choosingWeapon) {
                                    System.out.println("\n--- Your Weapons ---");
                                    for (int i = 0; i < player.getInventory().getWeapons().size(); i++) {
                                        Weapon w = player.getInventory().getWeapons().get(i);
                                        String equipped = (w == player.getWeapon()) ? GREEN + " (Equipped)" + RESET : "";
                                        System.out.println((i + 1) + ". " + w.getName() + " (Damage: " + w.getDamage() + ")" + equipped);
                                    }
                                    System.out.println("0. Back To Equipment Menu");
                                    System.out.println("\nEnter Number Of Weapon To Equip:");
                                    try {
                                        int eqW = Integer.parseInt(scanner.nextLine());
                                        if (eqW == 0) {
                                            choosingWeapon = false;
                                        } else if (eqW > 0 && eqW <= player.getInventory().getWeapons().size()) {
                                            player.equipWeapon(eqW - 1);
                                        } else {
                                            System.out.println("Invalid Selection.");
                                        }
                                    } catch (NumberFormatException e) {
                                        System.out.println("Invalid Selection.");
                                    }
                                }
                                break;

                            case "2":
                                boolean choosingArmor = true;
                                while (choosingArmor) {
                                    System.out.println("\n--- Your Armors ---");
                                    for (int i = 0; i < player.getInventory().getArmors().size(); i++) {
                                        Armor a = player.getInventory().getArmors().get(i);
                                        String equipped = (a == player.getArmor()) ? GREEN + " (Equipped)" + RESET : "";
                                        System.out.println((i + 1) + ". " + a.getName() + " (Defense: " + a.getDefense() +" | Durability: " + a.getDurability() + ")" + equipped);
                                    }
                                    System.out.println("0. Back To Equipment Menu");
                                    System.out.println("\nEnter Number Of Armor To Equip And Repair (" + YELLOW + "20" + RESET + " Coins) If Needed:");
                                    try {
                                        int eqA = Integer.parseInt(scanner.nextLine());
                                        if (eqA == 0) {
                                            choosingArmor = false;
                                        } else if (eqA > 0 && eqA <= player.getInventory().getArmors().size()) {
                                            Armor selectedArmor = player.getInventory().getArmors().get(eqA - 1);
                                            if (selectedArmor.getDurability() < 100) {
                                                if (player.getCoins() > 20) {
                                                    selectedArmor.repair();
                                                    player.spendCoins(20);
                                                } else {
                                                    System.out.println(RED + "Not Enough Coins!" + RESET);
                                                }
                                            }
                                            player.equipArmor(eqA - 1);
                                        } else {
                                            System.out.println("Invalid Selection.");
                                        }
                                    } catch (NumberFormatException e) {
                                        System.out.println("Invalid Selection.");
                                    }
                                }
                                break;
                            case"3":
                                boolean viewingPotions = true;
                                while (viewingPotions) {
                                    System.out.println("\n--- Your Items ---");

                                    player.getInventory().showMiscItems();

                                    System.out.println("0. Back To Equipment Menu");
                                    String potionChoice = scanner.nextLine();

                                    if (potionChoice.equals("0")) {
                                        viewingPotions = false;
                                    } else {
                                        System.out.println("Invalid Selection.");
                                    }
                                }
                                break;

                            case "0":
                                managing = false;
                                break;
                            default:
                                System.out.println("Invalid Selection.");
                        }
                    }
                    break;

                case "0":
                    System.out.println("Come Back Anytime.");
                    inShop = false;
                    break;

                default:
                    System.out.println("Invalid Selection.");
            }
        }
    }
}