package org.project;

import org.project.entity.enemies.*;
import org.project.entity.players.Assassin;
import org.project.entity.players.Knight;
import org.project.entity.players.Player;
import org.project.entity.players.Wizard;
import org.project.location.Location;

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

public class Main {

    private static List<Location> locations = new ArrayList<>();
    public static Player player;
    private static Enemy enemy;
    private static int currentLocationIndex;

    public static void main(String[] args) {
        createPlayer();
        setupLocations();
        gameLoop();
    }

    public static void gameLoop() {

        while (player.isAlive()) {

            chooseLocation();
            spawnRandomEnemy();
            if(enemy != null) handleLocation();

        }
    }
    public static void createPlayer() {

        Scanner in = new Scanner(System.in);
        System.out.println("Welcome to Java Knight ⚔\uFE0F\nPlease enter your name: ");
        String name = in.nextLine();
        System.out.println("Hi " + name + "\uD83C\uDF89\n");


        while (true){

            System.out.println("Choose your character: \n" +
                    "1. Knight⚔️\n" +
                    "2. Wizard\uD83E\uDDD9\u200D♂️\n" +
                    "3. Assassin\uD83D\uDDE1️");


            int choice = in.nextInt();
            switch (choice) {

                case 1:
                    player = new Knight(name);
                    System.out.println("You are a KNIGHT⚔️\n");
                    return;
                case 2:
                    player = new Wizard(name);
                    System.out.println("You are a Wizard\uD83E\uDDD9\u200D♂️\n");
                    return;
                case 3:
                    player = new Assassin(name);
                    System.out.println("You are a Assassin\uD83D\uDDE1\n️️");
                    return;
                default:
                    System.out.println("\u001B[31m❌Invalid choice❌\u001B[0m");
                    break;
            }
        }
    }

    public static void setupLocations() {

        ArrayList<Enemy> CryptEnemies = new ArrayList<>();
        CryptEnemies.add(new Skeleton());
        CryptEnemies.add(new Goblin());
        locations.add(new Location("Crypt", CryptEnemies));


        ArrayList<Enemy> WarrensEnemies = new ArrayList<>();
        WarrensEnemies.add(new Goblin());
        WarrensEnemies.add(new Goblin());
        WarrensEnemies.add(new Skeleton());
        locations.add(new Location("Warrens️", WarrensEnemies));


        ArrayList<Enemy> ManorEnemies = new ArrayList<>();
        ManorEnemies.add(new Vampire());
        ManorEnemies.add(new Skeleton());
        locations.add(new Location("Manor️", ManorEnemies));


        ArrayList<Enemy> CourtyardEnemies = new ArrayList<>();
        CourtyardEnemies.add(new Vampire());
        CourtyardEnemies.add(new Goblin());
        CourtyardEnemies.add(new Skeleton());
        locations.add(new Location("Courtyard", CourtyardEnemies));


        ArrayList<Enemy> CatacombsEnemies = new ArrayList<>();
        CatacombsEnemies.add(new Skeleton());
        CatacombsEnemies.add(new Goblin());
        CatacombsEnemies.add(new Vampire());
        CatacombsEnemies.add(new Goblin());
        locations.add(new Location("Catacombs", CatacombsEnemies));

    }

    public static void chooseLocation() {

        System.out.println("Select your destination \uD83C\uDFAF");

        Scanner in = new Scanner(System.in);

        while (true) {

            for(int i=0 ; i<locations.size() ; i++) {
                System.out.println((i+1) +". "+ locations.get(i).getName());
            }

            int choice = in.nextInt();
            if(choice>0 && choice<=locations.size()) {
                currentLocationIndex = choice - 1;
                System.out.println("\uD83D\uDCCD Location: " + locations.get(currentLocationIndex).getName());
                return;
            }
            else
                System.out.println("\u001B[31m❌Invalid choice❌\u001B[0m\nChoose another option: ");
        }
    }

    public static void spawnRandomEnemy() {

        ArrayList<Enemy> enemies = locations.get(currentLocationIndex).getEnemies();
        Random random = new Random();
        if(enemies.isEmpty()) {
            System.out.println("No enemies found in " + locations.get(currentLocationIndex).getName() + "...\n");
            enemy = null;
            return;
        }
        int currentEnemyIndex = random.nextInt(enemies.size());
        enemy = locations.get(currentLocationIndex).getEnemy(currentEnemyIndex);
        System.out.println("You're facing a " + enemy.getType());

    }


    public static void handleLocation() {

        System.out.println("What next?");

        Scanner in = new Scanner(System.in);
        while (true) {

            System.out.println("1. Fight the " + enemy.getType() + "\uD83E\uDD4A" +
                    "\n2. Go to another location\uD83D\uDCCD\n" +
                    "3. Go to the Castle to fight the Dragon\uD83D\uDC09");

            int choice = in.nextInt();

            switch (choice) {
                case 1:
                    fight();
                    return;
                case 2:
                    return;
                case 3:
                    if(player.hasGoblinKey() && player.hasVampireKey() && player.hasSkeletonKey()) {
                        enemy = new Dragon();
                        fight();
                        return;
                    }
                    else {
                        System.out.println("You don't have all the keys\uD83D\uDD12\n");
                        break;
                    }
                default:
                    System.out.println("\u001B[31m❌Invalid choice❌\u001B[0m\nChoose another option: ");
                    break;
            }
        }
    }

    public static void fight() {

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

            System.out.println("\n[" + player.getName() + " - "
                    + player.getMp() + "/" + player.getMaxMP() + " MP | "
                    + player.getHP() + "/" + player.getMaxHP() + " HP]");

            System.out.println('[' + enemy.getType() + " - "
                    + enemy.getHP() + "/" + enemy.getMaxHP() + " HP]\n");

            playerTurn();

            if(enemy.isAlive())
                enemyTurn();
        }

        if(!player.isAlive()) {
            System.out.println("💀 You have been defeated...");
            player.setXp(0);
            player.setGoblinKey(false);
            player.setVampireKey(false);
            player.setSkeletonKey(false);
            setupLocations();
        }

        else if(!enemy.isAlive()) {
            handleEnemyDeath();
        }
    }

    public static void playerTurn() {

        System.out.println("Your turn: ");
        Scanner in = new Scanner(System.in);

        while (true) {

            System.out.println("1.light attack\n" +
                    "2.heavy attack (\u001B[31m-" + player.getHeavyAttackManaCost() + " Mana\u001B[0m)" +
                    "\n3.defend (\u001B[31m-" + player.getDefendManaCost() + " Mana\u001B[0m)" +
                    "\n4.heal (\u001B[31m-" + player.getHealManaCost()+ " Mana\u001B[0m)" +
                    "\n5.special move (\u001B[31m-" + player.getSpecialAbilityManaCost() + " Mana\u001B[0m)");
            int choice = in.nextInt();

            int manaCost;

            switch (choice) {
                case 1:
                    player.lightAttack(enemy);
                    return;
                case 2:
                    manaCost = player.getHeavyAttackManaCost();
                    break;
                case 3:
                    manaCost = player.getDefendManaCost();
                    break;
                case 4:
                    manaCost = player.getHealManaCost();
                    break;
                case 5:
                    manaCost = player.getSpecialAbilityManaCost();
                    break;
                default:
                    System.out.println("\u001B[31m❌Invalid choice❌\u001B[0m\nChoose another option: ");
                    continue;
            }

            if(player.reduceMana(manaCost)) {

                if(choice == 2) player.heavyAttack(enemy);
                else if (choice == 3 && !(enemy instanceof Dragon)) player.defend();
                else if (choice == 4) player.heal(20);
                else if(choice == 5) player.specialAbility(enemy);

                return;
            }
            else
                System.out.println("You don't have enough Mana\nChoose another...");

        }
    }

    public static void enemyTurn() { enemy.attack(player);}

    public static void handleEnemyDeath() {

        if(enemy instanceof Skeleton && ((Skeleton) enemy).getReviveEnabled()) {
            ((Skeleton) enemy).revive();
            fight();
        }
        else if(enemy instanceof Dragon) {
            System.out.println("\nCongratulations! You defeated the Dragon and won!\uD83C\uDFC6");
        }
        else{
            System.out.println("\nYou won the battle!\uD83C\uDF89");
            player.addXP(enemy.getXpReward());
            System.out.println("You gained " + enemy.getXpReward() + " XP");
            player.fillMana(player.getMaxMP());
            player.heal(player.getMaxHP());
            System.out.println("\u001B[32mHP and Mana fully restored\u001B[0m\n");
            tryDropKey();
            locations.get(currentLocationIndex).getEnemies().remove(enemy);
        }

    }

    public static void tryDropKey() {

        if(Math.random()<0.2) {
            if(enemy instanceof Goblin && !player.hasGoblinKey()) {
                player.setGoblinKey(true);
                System.out.println("You got Goblin key\uD83D\uDD11\n");
            }
            else if(enemy instanceof Skeleton && !player.hasSkeletonKey()) {
                player.setSkeletonKey(true);
                System.out.println("You got skeleton key\uD83D\uDD11\n");
            }
            else if(enemy instanceof Vampire && !player.hasVampireKey()) {
                player.setVampireKey(true);
                System.out.println("You got Vampire key\uD83D\uDD11\n");
            }
        }
    }
}