package org.project;

import org.project.entity.Entity;
import org.project.entity.enemies.*;
import org.project.entity.players.Player;
import org.project.location.Location;
import java.util.ArrayList;
import java.util.Random;
import java.util.Scanner;
import static org.project.ConsoleColors.*;

public class MenuActions {      //this class contains main game logic.
    private ArrayList<Location> locations;
    Scanner scanner;

    public MenuActions() {
        this.scanner = new Scanner(System.in);
        this.locations = new ArrayList<>();
    }

    public void startGame(Player player) {   // gameplay starts from here
        Skeleton.resetKeysRemaining();
        Goblin.resetKeysRemaining();
        Vampire.resetKeysRemaining();
        while (player.getKeysCollectedCount() < 3) {        //player keeps fighting until all 3 keys are collected
            askInventory(player);
            Enemy enemy = chooseEnemy();
            Entity winner = fight(player, enemy);
            if (winner != player) {
                System.out.println(RED + "Game over!\nreturning to main menu..." + RESET);
                break;
            }
        }
        if (player.getKeysCollectedCount() == 3) {
            bossFight(player);
        }
    }

    private void bossFight(Player player) {
        System.out.println(GREEN + "Congratulations! You have successfully collected all 3 keys\n" +
                "You may now fight the Dragon" + RESET);
        System.out.println(YELLOW + "Make sure to upgrade before entering the castle!" + RESET);
        askInventory(player);
        System.out.println(CYAN + "Entering the castle..." + RESET);
        Entity winner = fight(player, new Dragon());
        if (winner != player) {
            System.out.println(RED + "You were killed by the dragon. Game over!\nreturning to main menu..." + RESET);
        } else {
            System.out.println(GREEN + BOLD + "Congratulations! You killed the dragon and saved Javanest!" + RESET);
        }
    }

    private Enemy chooseEnemy() {
        while (true) {
            Location location = new Location();
            Enemy enemy = location.getEnemies().get(0);
            String enemyName = enemy.getType();
            System.out.println(CYAN + "====================================" + RESET);
            System.out.println("You are in the " + YELLOW + location.getName() + RESET +
                    ".\nYou may fight with a " + enemyName);
            System.out.println("Which option do you choose?" +"\n1- Fight with the "
                    + enemyName + "\n2- Skip to Another Location");
            outerLoop:
            while (true) {
                int choice = getValidIntInput();
                switch (choice) {
                    case 1:
                        return enemy;
                    case 2:
                        System.out.println("You chose not to fight...Skipping to next location...");break outerLoop;
                    default:
                        System.out.println(RED + "Invalid choice. Please choose a number (1 or 2)." + RESET);
                }
            }
        }
    }

    public Entity fight(Player player, Enemy enemy) {
        player.heal(player.getMaxHP());
        player.fillMana(player.getMaxMP());
        Entity winner;
        while (true) {
            playerTurn(player, enemy);
            if (enemy.getHp() == 0) {
                winner = player;
                System.out.println(GREEN + player.getName() + " won the fight!" + RESET);
                if (!(enemy instanceof Dragon)) {
                    player.setXp(player.getXp()+5);
                    System.out.println(GREEN + player.getName() + " got 5 XP for winning the fight!" + RESET);
                }

                if (enemy instanceof Skeleton) {
                    boolean hasKey = ((Skeleton) enemy).generateKey();
                    if (hasKey) {
                        player.collectKey((Skeleton) enemy);
                        player.setXp(player.getXp()+20);
                        System.out.println(GREEN + player.getName() + " got a Skeleton key and 20 XP!" + RESET);
                    }
                }
                if (enemy instanceof Goblin) {
                    boolean hasKey = ((Goblin) enemy).generateKey();
                    if (hasKey) {
                        player.collectKey((Goblin) enemy);
                        player.setXp(player.getXp()+10);
                        System.out.println(GREEN + player.getName() + " got a Goblin key and 10 XP!" + RESET);
                    }
                }
                if (enemy instanceof Vampire) {
                    boolean hasKey = ((Vampire) enemy).generateKey();
                    if (hasKey) {
                        player.collectKey((Vampire) enemy);
                        player.setXp(player.getXp()+30);
                        System.out.println(GREEN + player.getName() + " got a Vampire key and 30 XP!" + RESET);
                    }
                }
                System.out.println("Keys collected: " + player.getStringKeysCollected());
                return winner;
            }
            enemyTurn(player, enemy);
            if (player.getHp() == 0) {
                winner = enemy;
                System.out.println(RED + winner.getType() + " won the fight!" + RESET);
                return winner;
            }
        }
    }

    private void enemyTurn(Player player, Enemy enemy) {
        System.out.println(CYAN + "====================================" + RESET);
        System.out.println(YELLOW + "Enemy turn. Let's see what it does!" + RESET);
        System.out.println("Your hp: " + player.getHp() + "/" + player.getMaxHP());
        System.out.println("Enemy hp: " + enemy.getHp() + "/" + enemy.getMaxHP());
        while (true) {
            Random random = new Random();
            int choice = random.nextInt(3) + 1;
            switch (choice) {
                case 1: enemy.getWeapon().lightAttack(player);
                    System.out.println(enemy.getType() + " attacked(light)!"); return;
                case 2: if(enemy.getMp() >= enemy.getWeapon().getManaCost()) {
                    enemy.getWeapon().heavyAttack(enemy, player);
                    System.out.println(enemy.getType() + " attacked(Heavy)!"); return;
                } break;
                case 3: if (enemy.getMp() >= enemy.getWeapon().getSpecialMana()){
                    enemy.getWeapon().useSpecialAbility(enemy, player);
                    System.out.println(enemy.getType() + " used special ability!"); return;
                } break;
                default:
                    System.out.println(RED + "Invalid choice" + RESET);
            }
        }
    }

    private void playerTurn(Player player, Enemy enemy) {
        System.out.println(CYAN + "====================================" + RESET);
        System.out.println(YELLOW + "Player turn. What do you want to do?" + RESET);
        System.out.println("Your hp: " + player.getHp() + "/" + player.getMaxHP() +
                "\t Your mana: " + player.getMp() + "/" + player.getMaxMP());
        System.out.println("Enemy hp: " + enemy.getHp() + "/" + enemy.getMaxHP());
        System.out.println("1-Light attack, mana cost: 0");
        System.out.println("2-Heavy attack, mana cost: " + player.getWeapon().getManaCost());
        System.out.println("3-Special Ability, mana cost: " + player.getWeapon().getSpecialMana());
        System.out.println("4-Defend, mana cost: " + player.getDefendManaCost());
        System.out.println("5-Heal, mana cost: " + player.getHealManaCost());
        while (true) {
            int choice = getValidIntInput();
            switch (choice) {
                case 1: player.getWeapon().lightAttack(enemy);
                    System.out.println("You chose light attack.");return;
                case 2: if(player.getMp() >= player.getWeapon().getManaCost()) {
                    player.getWeapon().heavyAttack(player, enemy);
                    System.out.println("You chose heavy attack.");return;
                } else {
                    System.out.println(RED + "Not enough mana. Choose Again: " + RESET); break;
                }
                case 3: if (player.getMp() >= player.getWeapon().getSpecialMana()){
                    player.getWeapon().useSpecialAbility(player, enemy);
                    System.out.println("You chose special ability.");return;
                } else {
                    System.out.println(RED + "Not enough mana. Choose Again: " + RESET); break;
                }
                case 4: if (player.getMp() >= player.getDefendManaCost())  {
                    player.defend();
                    System.out.println("You chose to defend."); return;
                } else {
                    System.out.println(RED + "Not enough mana. Choose Again: " + RESET); break;
                }
                case 5: if (player.getMp() >= player.getHealManaCost()) {
                    player.heal(20); return;
                } else {
                    System.out.println(RED + "Not enough mana. Choose Again:" + RESET);
                    System.out.println("You chose to heal yourself.");break;
                }
                default:
                    System.out.println(RED + "Invalid choice" + RESET);
            }
        }
    }

    private void askInventory(Player player) {
        whileLoop:
        while (true) {
            System.out.println("Choose an option: ");
            System.out.println("1- Go to the inventory");
            System.out.println("2- Continue to next fight");
            int choice = getValidIntInput();
            switch (choice) {
                case 1: shop(player); break;
                case 2: return;
                default:
                    System.out.println(RED + "Invalid choice, please choose a number (1 or 2)." + RESET); break;
            }
        }
    }

    private void shop(Player player) {
        while (true) {
            System.out.println(CYAN + "=====Shop=====" + RESET);   // exactly original string
            System.out.println("You have " + YELLOW + player.getXp() + " XP" + RESET);
            System.out.println("Each experience point can be converted into either 1 mana or 1 hp");
            System.out.println("Which option do you choose?");
            System.out.println("1- Buy hp");
            System.out.println("2- Buy mana");
            System.out.println("0- Back");
            switchLoop:
            while(true) {
                int choice = getValidIntInput();
                switch (choice) {
                    case 1:
                        while (true) {
                            System.out.println("Enter amount: " + "\tShould be less than or equal to " + player.getXp());
                            int amount = getValidIntInput();
                            if (amount <= player.getXp()) {
                                player.buyHp(amount);
                                System.out.println(GREEN + "Successfully bought " + amount + " hp." + RESET);
                                System.out.println("Current hp and mana: " + "\thp: " + player.getMaxHP() +"\tmana: " + player.getMaxMP());
                                break switchLoop;
                            } else if (amount > player.getXp()) {
                                System.out.println(RED + "Not enough XP" + RESET);
                            }
                        }
                    case 2:
                        while (true) {
                            System.out.println("Enter amount: " + "\tShould be less than or equal to " + player.getXp());
                            int amount = getValidIntInput();
                            if (amount <= player.getXp()) {
                                player.buyMp(amount);
                                System.out.println(GREEN + "Successfully bought " + amount + " mana." + RESET);
                                System.out.println("Current maximum hp and mana: " + "\thp: " + player.getMaxHP() +"\tmana: " + player.getMaxMP());
                                break switchLoop;
                            } else if (amount > player.getXp()) {
                                System.out.println(RED + "Not enough XP" + RESET);
                            }
                        }
                    case 0: return;
                    default:
                        System.out.println(RED + "Invalid choice. Please choose a number from 0-2." + RESET);
                }
            }
        }
    }

    private int getValidIntInput() {
        while (!scanner.hasNextInt()) {
            System.out.print(RED + "Please enter a valid number: " + RESET);
            scanner.next();
        }
        int input = scanner.nextInt();
        scanner.nextLine(); // Clear buffer
        return input;
    }
}