package de.siphalor.was.visual;

import de.siphalor.was.WhatAStorage;
import de.siphalor.was.content.lang.I18n;
import de.siphalor.was.content.product.Product;
import de.siphalor.was.content.quest.Quest;
import de.siphalor.was.game.Balance;
import de.siphalor.was.game.Transaction;

import java.util.Arrays;
import java.util.Scanner;
import java.util.stream.Collectors;

public class ConsoleVisual implements Visual {
	private final int CELL_WIDTH = 16;

	private WhatAStorage was;
	private Scanner scanner;

	private State state;

	private String[][][] storage;
	private int budget;

	private enum State {
		MENU, GAME,
	}

	@Override
	public void setup(WhatAStorage whatAStorage) {
		state = State.MENU;
		was = whatAStorage;
		scanner = new Scanner(System.in);
	}

	@Override
	public void run() {
		loop:
		while (true) {
			String input = scanner.nextLine();
			String[] parts = input.split(" ");
			if (parts.length == 0) continue;
			switch (state) {
				case MENU:
					switch (parts[0]) {
						case "help": {
							I18n i18n = I18n.getInstance();
							System.out.println("start: " + i18n.getString("menu.start-game"));
							System.out.println("exit:  " + i18n.getString("game.quit"));
							break;
						}
						case "start":
							was.startGame("random");
							break;
						case "exit":
							was.scheduleStop();
							break loop;
						default:
							printInvalidInput();
							break;
					}
					break;
				case GAME:
					switch (parts[0]) {
						case "help": {
							I18n i18n = I18n.getInstance();
							System.out.println("status:  " + i18n.getString("game.storage"));
							System.out.println("budget:  " + i18n.getString("game.budget"));
							System.out.println("options: " + i18n.getString("menu.options"));
							System.out.println("exit:    " + i18n.getString("game.quit"));
							break;
						}
						case "status": {
							showGame();
							System.out.println();
							Balance balance = WhatAStorage.getInstance().getBalance();
							showBudget(balance.getBudget(), balance.getTotalIncome(), balance.getTotalLoss());
							break;
						}
						case "budget": {
							Balance balance = WhatAStorage.getInstance().getBalance();
							showBudget(balance.getBudget(), balance.getTotalIncome(), balance.getTotalLoss());
							break;
						}
						case "exit":
							was.scheduleStop();
							break loop;
						case "options":
							if (parts.length == 1) {
								System.out.println(I18n.getInstance().getString("menu.options.available"));
								System.out.println("lang");
							} else {
								switch (parts[1]) {
									case "lang":
										if (parts.length == 2) {
											System.out.println(Arrays.stream(WhatAStorage.getInstance().getLangs()).map(s ->
													s + ": " + I18n.getInstance().getString("langs." + s)
											).collect(Collectors.joining(", ")));
										} else {
											if (I18n.getInstance().setLang(parts[2], WhatAStorage.getInstance().getContentManager())) {
												invalidateI18n();
												WhatAStorage.getInstance().getOptions().save();
											} else {
												printInvalidInput();
											}
										}
										break;
									default:
										printInvalidInput();
										break;
								}
							}
							break;
						default:
							printInvalidInput();
							break;
					}
					break;
			}
		}
	}

	private void showGame() {
		int width = storage.length;
		int height = storage[0].length;
		int depth = storage[0][0].length;
		int index = 1;

		final String empty = I18n.getInstance().getString("game.storage.empty");
		for (int y = 0; y < height; y++) {
			{
				StringBuilder stringBuilder = new StringBuilder();
				for (int x = 0; x < width; x++) {
					stringBuilder.append(index);
					stringBuilder.append(".");
					stringBuilder.append(" ".repeat(CELL_WIDTH * (x + 1) + x * 3 - stringBuilder.length()));
					if (x < width - 1) {
						stringBuilder.append(" | ");
					}

					index++;
				}
				System.out.println(stringBuilder.toString());
			}

			for (int z = 0; z < depth; z++) {
				StringBuilder stringBuilder = new StringBuilder();
				for (int x = 0; x < width; x++) {
					if (storage[x][y][z] != null) {
						stringBuilder.append(I18n.getInstance().getString(storage[x][y][z]));
					} else {
						stringBuilder.append(empty);
					}
					stringBuilder.append(" ".repeat(CELL_WIDTH * (x + 1) + x * 3 - stringBuilder.length()));
					if (x < width - 1) {
						stringBuilder.append(" | ");
					}
				}
				System.out.println(stringBuilder.toString());
			}

			if (y < height - 1) {
				StringBuilder stringBuilder = new StringBuilder();
				for (int x = 0; x < width; x++) {
					stringBuilder.append("-".repeat(CELL_WIDTH));
					if (x < width - 1) {
						stringBuilder.append("-+-");
					}
				}
				System.out.println(stringBuilder.toString());
			}
		}
	}

	private void showBudget(int budget, int totalIncome, int totalLoss) {
		I18n i18n = I18n.getInstance();

		System.out.println(i18n.format("game.budget.label", budget) +
				"    " +
				i18n.format("game.balance.total-income", totalIncome) +
				"    " +
				i18n.format("game.balance.total-loss", totalLoss));
	}

	private void printInvalidInput() {
		System.out.println(I18n.getInstance().getString("general.invalid-input"));
	}

	@Override
	public void onGameStart(int width, int height, int depth) {
		storage = new String[width][height][depth];
		state = State.GAME;

		showGame();
		System.out.println();
		showBudget(0, 0, 0);
	}

	@Override
	public void onScheduleStop() {

	}

	@Override
	public void invalidateI18n() {

	}

	@Override
	public void onBalanceChanged(int budget, Transaction transaction, int totalIncome, int totalLoss) {

	}

	@Override
	public void onQuestAdded(Quest newQuest, boolean canCreateMore) {

	}

	@Override
	public void onQuestRemoved(int index) {

	}

	@Override
	public void onProductSet(int x, int y, int z, Product product) {

	}

	@Override
	public void onProductCleared(int x, int y, int z, Product product) {

	}
}
