package org.project;

import org.project.entity.players.*;
import org.project.entity.enemies.*;
import org.project.location.*;
import org.project.item.weapons.*;
import org.project.item.consumables.*;
import org.project.item.armors.*;

import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;

public class Main {
    private static Scanner scanner = new Scanner(System.in);
    private static Random random = new Random();

    private static Player player;

    //Collected keys
    private static boolean hasGoblinKey = false;
    private static boolean hasSkeletonKey = false;
    private static boolean hasVampireKey = false;

    private static boolean castleUnlocked = false;

    public static void main(String[] args) {
        System.out.println("⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️");
        NarrativeConsole.printNormal("                 JAVA KNIGHT - THE DRAGON'S CURSE");
        System.out.println("⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️⚔️");
        NarrativeConsole.printNormal("\nFor centuries, the land of Javanest lived in peace...");
        NarrativeConsole.printNormal("Until a magical Dragon attacked, plunging the realm into darkness!");
        NarrativeConsole.printNormal("You are the last hope. Gather the 3 keys and slay the Dragon!\n");

        //Choosing a role
        createPlayer();

        gameLoop();
    }

    private static void createPlayer() {
        System.out.println("=".repeat(20));
        System.out.println("CHOOSE YOUR HERO:");
        System.out.println("1. Knight ⚔️   - High damage, strong armor");
        System.out.println("2. Wizard 🧙‍♂️  - High HP, healing spells");
        System.out.println("3. Assassin 🗡️ - High mana, critical strikes");
        System.out.print("\nEnter choice (1-3): ");

        int choice = getIntInput();
        scanner.nextLine();

        System.out.print("Enter your hero's name: ");
        String name = scanner.nextLine();

        switch (choice) {
            case 1:
                player = new Knight(name);
                break;
            case 2:
                player = new Wizard(name);
                break;
            case 3:
                player = new Assassin(name);
                break;
            default:
                System.out.println("Invalid choice! Defaulting to Knight.");
                player = new Knight(name);
        }

        System.out.println("\n✨ " + player.getName() + " the " +
                player.getClass().getSimpleName() + " has entered Javanest!");
        NarrativeConsole.printHeal("💚 HP: " + player.getHp() + "/" + player.getMaxHP());
        NarrativeConsole.printMana("💙 MP: " + player.getMp() + "/" + player.getMaxMP());
        System.out.println("\nPress Enter to begin your journey...");
        scanner.nextLine();
    }

    private static void gameLoop() {
        boolean gameRunning = true;
        boolean firstLocation = true;

        while (gameRunning && player.isAlive()) {
            //Entering a new location
            if (!firstLocation) {
                System.out.println("\n" + "=".repeat(30));
                System.out.println("You move to a new location...");
            }
            firstLocation = false;

            Enemy currentEnemy = spawnRandomEnemy();
            NarrativeConsole.printWarning("\n⭕⭕⭕ A " +
                    currentEnemy.getName(currentEnemy).toUpperCase() + " appears before you! ⭕⭕⭕");
            NarrativeConsole.printWarning("❤️ " + currentEnemy.getName(currentEnemy) + " HP: " +
                    currentEnemy.getHp() + "/" + currentEnemy.getMaxHP());

            //Pre-battle menu
            boolean locationExited = false;

            while (!locationExited && player.isAlive() && gameRunning) {
                displayMainMenu();
                int choice = getIntInput();

                if (choice == 1) {
                    //Option 1: Starting the battle
                    boolean victory = startBattle(currentEnemy);

                    if (victory) {
                        handleVictory(currentEnemy);
                        locationExited = true; //Moving on the next location
                    } else {
                        gameRunning = false; //Player's death
                    }

                } else if (choice == 2) {
                    //Option 2: Move to another location1
                    System.out.println("\n🚶 You flee to another location...");
                    currentEnemy = spawnRandomEnemy();
                    NarrativeConsole.printWarning("⭕ A " + currentEnemy.getName(currentEnemy) +
                            " appears in this new location!");

                } else if (choice == 3 && castleUnlocked) {
                    //Option 3: Going to the castle and fight the dragon (only with 3 keys)
                    System.out.println("\n🏰🏰🏰 YOU STAND BEFORE THE DRAGON'S CASTLE! 🏰🏰🏰");
                    System.out.println("The gates slowly open... A massive shadow emerges...\n");

                    boolean victory = startBattle(new Dragon());
                    if (victory) {
                        System.out.println("\n🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉");
                        NarrativeConsole.printSuccess("     THE DRAGON IS DEFEATED! YOU SAVED JAVANEST!");
                        System.out.println("🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉🎉");
                        gameRunning = false;
                    } else {
                        NarrativeConsole.printError("\n💀 The Dragon's flames consume you... GAME OVER!");
                        gameRunning = false;
                    }
                    break;
                }

                //Checking the condition for opening the castle
                if (hasAllKeys() && !castleUnlocked) {
                    castleUnlocked = true;
                    System.out.println("\n🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑");
                    NarrativeConsole.printSuccess("     YOU HAVE COLLECTED ALL 3 KEYS!");
                    NarrativeConsole.printSuccess("🏰 THE PATH TO THE DRAGON'S CASTLE IS NOW OPEN! 🏰");
                    System.out.println("🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑🔑");
                }

                displayKeyProgress();

                //End game
                if (!player.isAlive()) {
                    NarrativeConsole.printError("\n💀💀💀 GAME OVER! 💀💀💀");
                    NarrativeConsole.printError("Your journey ends here. The curse of Javanest remains unbroken...");
                }
            }
        }
    }

    private static void displayMainMenu() {
        System.out.println("\n" + "-".repeat(30));
        System.out.println("WHAT WILL YOU DO?");
        System.out.println("1. ⚔️ FIGHT the enemy");
        System.out.println("2. 🚶 MOVE to another location");

        if (castleUnlocked) {
            System.out.println("3. 🏰 GO TO THE CASTLE (Fight the Dragon!)");
        }
        System.out.print("\nChoose: ");
    }

    private static boolean startBattle(Enemy enemy) {
        System.out.println("\n" + "🔥".repeat(30));
        System.out.println("                 BATTLE BEGINS!");
        System.out.println("🔥".repeat(30));

        while (player.isAlive() && enemy.isAlive()) {
            displayBattleStatus(enemy);

            playerTurn(enemy);
            if (!enemy.isAlive()) {
                break;
            }

            enemyTurn(enemy);
        }

        return player.isAlive();
    }

    private static void playerTurn(Enemy enemy) {
        System.out.println("\n" + "-".repeat(30));
        System.out.println("YOUR TURN");
        System.out.println("1. ⚔️ Light Attack (0 Mana)");
        System.out.println("2. 💥 Heavy Attack (-8 Mana)");
        System.out.println("3. 🛡️ Defend (-6 Mana)");
        System.out.println("4. 💚 Heal (-12 Mana)");
        System.out.println("5. ⭐ Special Ability (-15 Mana)");
        System.out.print("Choose action: ");

        int choice = getIntInput();

        switch (choice) {
            case 1:
                player.lightAttack(enemy);
                break;
            case 2:
                player.heavyAttack(enemy);
                break;
            case 3:
                player.defend();
                break;
            case 4:
                player.heal(12);
                break;
            case 5:
                player.specialAbility(enemy);
                break;
            default:
                NarrativeConsole.printWarning("❌ Invalid choice! You hesitate and lose your turn!");
        }

        //Checking the death of enemy
        if (!enemy.isAlive()) {
            NarrativeConsole.printSuccess("\n💀 " +
                    enemy.getName(enemy).toUpperCase() + " HAS BEEN DEFEATED! 💀");
        }
    }

    private static void enemyTurn(Enemy enemy) {
        System.out.println("\n" + "-".repeat(30));
        System.out.println("ENEMY TURN");
        enemy.attack(player);
    }

    private static void displayBattleStatus(Enemy enemy) {
        System.out.println("\n" + "═".repeat(45));
        System.out.printf("❤️ %s: %d/%d HP  |  💙 Mana: %d/%d%n",
                player.getName(), player.getHp(), player.getMaxHP(),
                player.getMp(), player.getMaxMP());
        System.out.printf("👾 %s: %d/%d HP%n",
                enemy.getName(enemy), enemy.getHp(), enemy.getMaxHP());
        System.out.println("═".repeat(45));
    }

    private static Enemy spawnRandomEnemy() {
        int roll = random.nextInt(3); // 0, 1, 2

        switch (roll) {
            case 0:
                return new Goblin();
            case 1:
                return new Skeleton();
            default:
                return new Vampire();
        }
    }

    private static void handleVictory(Enemy defeatedEnemy) {
        NarrativeConsole.printSuccess("\n✨✨✨ VICTORY! ✨✨✨");
        NarrativeConsole.printSuccess(defeatedEnemy.getName(defeatedEnemy).toUpperCase() +
                " has been defeated!");

        //Getting Higher Max HP and MP
        player.setMaxHP(player.getMaxHP() + getXpReward(defeatedEnemy)/5);
        player.setMaxMP(player.getMaxMP() + getXpReward(defeatedEnemy)/5);

        //Full HP and Mana Recovery (Post-Combat Recovery)
        player.setHp(player.getMaxHP());
        player.setMp(player.getMaxMP());
        NarrativeConsole.printHeal("💚 HP and Mana fully restored in higher levels!");

        //Key Drop (20% chance)
        attemptKeyDrop(defeatedEnemy);
    }

    private static int getXpReward(Enemy enemy) {
        if (enemy instanceof Goblin) return 50;
        if (enemy instanceof Skeleton) return 65;
        if (enemy instanceof Vampire) return 85;
        if (enemy instanceof Dragon) return 300;
        return 40;
    }

    private static void attemptKeyDrop(Enemy enemy) {
        //Checking if we already have this key or not
        if (enemy instanceof Goblin && hasGoblinKey) {
            return;
        }
        if (enemy instanceof Skeleton && hasSkeletonKey) {
            return;
        }
        if (enemy instanceof Vampire && hasVampireKey) {
            return;
        }

        //Dropping the key (20% Chance)
        int dropChance = random.nextInt(100);
        if (dropChance > 80) {
            if (enemy instanceof Goblin) {
                hasGoblinKey = true;
                NarrativeConsole.printSuccess("\n🔑🔑🔑 YOU FOUND THE GOBLIN KEY! (1/3) 🔑🔑🔑");
            } else if (enemy instanceof Skeleton) {
                hasSkeletonKey = true;
                NarrativeConsole.printSuccess("\n🔑🔑🔑 YOU FOUND THE SKELETON KEY! (2/3) 🔑🔑🔑");
            } else if (enemy instanceof Vampire) {
                hasVampireKey = true;
                NarrativeConsole.printSuccess("\n🔑🔑🔑 YOU FOUND THE VAMPIRE KEY! (3/3) 🔑🔑🔑");
            }
        } else {
            System.out.println("🔑 No key dropped this time... Keep fighting!");
        }
    }

    private static boolean hasAllKeys() {
        return hasGoblinKey && hasSkeletonKey && hasVampireKey;
    }

    private static void displayKeyProgress() {
        System.out.println("\n" + "-".repeat(40));
        System.out.println("KEY PROGRESS:");
        System.out.println("  " + (hasGoblinKey ? "👹" : "⬜") + " Goblin Key   " + (hasGoblinKey ? "(Obtained)" : "(Missing)"));
        System.out.println("  " + (hasSkeletonKey ? "💀" : "⬜") + " Skeleton Key " + (hasSkeletonKey ? "(Obtained)" : "(Missing)"));
        System.out.println("  " + (hasVampireKey ? "🦇" : "⬜") + " Vampire Key  " + (hasVampireKey ? "(Obtained)" : "(Missing)"));
        System.out.println("-".repeat(40));
    }

    private static int getIntInput() {
        while (true) {
            try {
                int input = Integer.parseInt(scanner.nextLine().trim());
                return input;
            } catch (NumberFormatException e) {
                NarrativeConsole.printWarning("❌ Invalid input! Please enter a number: ");
            }
        }
    }
}