<template>
  <!-- TODO: Can't seem to work with flexbox to an extent that makes me happy... -->

  <q-card class="column" style="width: 100%; min-width: 800px; height: 80vh;">
    <div class="col-2">
      <q-card-section class="row justify-evenly q-gutter-md">
        <q-input
          class="col-5"
          v-model="game_id"
          square
          filled
          autogrow
          maxlength="50"
          label="Game ID"
          type="text"
        />

        <q-input
          class="col-5"
          v-model="game_name"
          square
          filled
          autogrow
          maxlength="100"
          label="Game Name"
          type="text"
        />
      </q-card-section>

      <q-card-section class="row justify-evenly q-gutter-md">
        <q-input
          class="col-5"
          v-model="short_description"
          square
          filled
          maxlength="200"
          label="Short Description"
          type="text"
        />

        <div class="col-5 row justify-center self-center">
          <q-btn
            class="col"
            icon="edit"
            color="orange"
            label="Description"
            outline
            @click="description_dialog = true"
          ></q-btn>
        </div>
      </q-card-section>
    </div>

    <div class="col-9 q-pt-sm">
      <q-card-section class="full-height">
        <q-card
          flat
          bordered
          class="full-height"
        >
          <div class="column full-height">
            <div class="col-1">
              <q-card-section class=" q-pa-sm">
                <span class="text-h4">Goal Editor</span>
              </q-card-section>
            </div>

            <div class="col-11">
              <q-separator></q-separator>

              <q-scroll-area class="full-height">
                <q-tree
                  :nodes="nodes"
                  node-key="label"
                  v-model:expanded="expanded"
                >
                  <template v-slot:header-goal="prop">
                    <div class="row items-center">
                      <q-btn
                        icon="edit"
                        flat
                        round
                        size="sm"
                        color="orange"
                        @click="openEditGoalDialog(prop.node)"
                      />
                      <div>{{ prop.node.item?.name || prop.node.label }}</div>
                      <q-btn
                        v-if="prop.node.item?.description?.length"
                        icon="help_outline"
                        flat
                        round
                        size="sm"
                        @click="event => openInfoDialog(prop.node.item?.description, event)"
                      ></q-btn>
                      <q-badge
                        outline
                        v-for="tag in prop.node.item?.tags"
                        :key="tag"
                        :color="getColorForString(tag)"
                        class="q-ml-sm"
                      >
                        <div class="text-weight-bold q-my-xs">{{ tag }}</div>
                      </q-badge>
                    </div>
                  </template>

                  <template v-slot:header-goal-list="prop">
                    <div class="row items-center">
                      <q-btn
                        icon="edit"
                        flat
                        round
                        size="sm"
                        color="orange"
                        @click="event => openEditGoalListDialog(prop.node, event)"
                      />
                      <div>{{ prop.node.item?.name || prop.node.label }}</div>
                      <q-btn
                        v-if="prop.node.item?.description?.length"
                        icon="help_outline"
                        flat
                        round
                        size="sm"
                        @click="event => openInfoDialog(prop.node.item?.description, event)"
                      ></q-btn>
                      <q-badge
                        outline
                        color="orange"
                        class="q-ml-sm"
                      >
                        <div class="text-weight-bold q-my-xs">Goal List</div>
                      </q-badge>
                    </div>
                  </template>

                  <template v-slot:header-category="prop">
                    <div class="row items-center">
                      <q-btn
                        icon="edit"
                        flat
                        round
                        size="sm"
                        color="orange"
                        @click="event => openEditCategoryDialog(prop.node, event)"
                      />
                      <div>{{ prop.node.item?.name || prop.node.label }}</div>
                      <q-badge
                        outline
                        color="blue"
                        class="q-ml-sm"
                      >
                        <div class="text-weight-bold q-my-xs">Category</div>
                      </q-badge>
                    </div>
                  </template>

                  <!-- Add Goal -->
                  <template v-slot:header-add-goal="prop">
                    <div class="row items-center">
                      <q-btn
                        outline
                        icon="add"
                        label="Goal"
                        color="light-blue"
                        size="sm"
                        @click="openEditGoalDialog(prop.node)"
                      ></q-btn>
                    </div>
                  </template>

                  <!-- Add Goal List -->
                  <template v-slot:header-add-goal-list="prop">
                    <div class="row items-center">
                      <q-btn
                        outline
                        icon="add"
                        label="Goal List"
                        color="light-blue"
                        size="sm"
                        @click="event => openEditGoalListDialog(prop.node, event)"
                      ></q-btn>
                    </div>
                  </template>

                  <!-- Add Category -->
                  <template v-slot:header-add-category="prop">
                    <div class="row items-center">
                      <q-btn
                        outline
                        icon="add"
                        label="Category"
                        color="light-blue"
                        size="sm"
                        @click="event => openEditCategoryDialog(prop.node, event)"
                      ></q-btn>
                    </div>
                  </template>
                </q-tree>
              </q-scroll-area>
            </div>
          </div>
        </q-card>
      </q-card-section>
    </div>

    <div class="col-1">
      <q-card-actions class="full-height items-end">
        <q-space/>

        <q-btn
          flat
          color="red"
          icon="cancel"
          label="Cancel"
          :loading="loading"
          @click="cancel"
        />
        <q-btn
          flat
          color="green"
          icon="save"
          label="Save"
          :loading="loading"
          @click="saveGame"
        />
      </q-card-actions>
    </div>
  </q-card>

  <q-dialog v-model="description_dialog">
    <q-card
      class="column"
      flat
      bordered
      style="min-width: 700px; max-width: 80vw; min-height: 10vh; max-height: 70vh;"
    >
      <div class="col-1">
        <q-card-section>
          <span class="text-h4">Description Editor</span>
        </q-card-section>
      </div>

      <div class="col-6">
        <q-card-section>
          <q-input
            v-model="game_description"
            square
            filled
            counter
            autogrow
            maxlength="500"
            label="Description"
            type="text"
          />
        </q-card-section>
      </div>

      <div class="col-1">
        <q-card-actions class="full-height items-end">
          <q-btn
            flat
            color="red"
            icon="cancel"
            label="Preview"
            :loading="loading"
            @click="event => openInfoDialog(game_description, event)"
          />

          <q-space/>

          <q-btn
            flat
            color="red"
            icon="cancel"
            label="Save"
            :loading="loading"
          />
        </q-card-actions>
      </div>
    </q-card>
  </q-dialog>

  <q-dialog v-model="info_dialog">
    <q-card
      flat
      bordered
      style="min-width: 700px; max-width: 80vw; min-height: 10vh; max-height: 80vh;"
    >
      <q-card-section>
        <MarkdownRenderer :text="info_dialog_text"/>
      </q-card-section>
    </q-card>
  </q-dialog>

  <q-dialog v-model="edit_goal_dialog" persistent>
    <EditGoalDialog
      :data="edit_goal_data"
      @cancel="edit_goal_dialog = false"
      @create-goal="create_goal"
      @update-goal="update_goal"
      @delete-goal="delete_goal"
    />
  </q-dialog>

  <q-dialog v-model="edit_goal_list_dialog" persistent>
    <EditGoalListDialog
      :data="edit_goal_list_data"
      @cancel="edit_goal_list_dialog = false"
      @create-goal-list="create_goal_list"
      @update-goal-list="update_goal_list"
      @delete-goal-list="delete_goal_list"
    />
  </q-dialog>
</template>

<script setup lang="ts">
interface Node {
	item?: BingoGoal | BingoGoalList | BingoCategory;
	parent?: BingoCategory | BingoGoalList;

	label: string;
	header?: string; // 'goal' | 'goal-list' | 'category' | 'add-goal' | 'add-goal-list' | 'add-category'

	children?: Node[];
}

import {
	getColorForString
} from '@/js/lib/Util.ts';

import BingoCategory from '@/js/lib/BingoCategory.ts';
import BingoGame from '@/js/lib/BingoGame.ts';
import BingoGoal from '@/js/lib/BingoGoal.ts';
import BingoGoalList from '@/js/lib/BingoGoalList.ts';
import Parser from '@/js/lib/Parser.ts';

const props = defineProps<{
	game?: BingoGame;
}>();

const emit = defineEmits([
	'cancel',
	'addGame',
	'updateGame'
]);

const game = ref(
	props.game
		? Parser.getCopy(props.game)
		: new BingoGame('new-game', 'New Game', 'A short description', 'A long description')
);
game.value.is_local = true;

const game_id = ref(game.value.id);
const game_name = ref(game.value.name);
const short_description = ref(game.value.short_description);
const game_description = ref(game.value.description.substring(0, 500));
const description_dialog = ref(false);

const expanded = ref<Node[]>([]);

const loading = ref(false);

function cancel() {
	loading.value = true;

	emit('cancel');
}

function saveGame() {
	loading.value = true;

	// Updating game
	if (props.game) {
		game.value.id = game_id.value;
		game.value.name = game_name.value;
		game.value.short_description = short_description.value;
		game.value.description = game_description.value;

		emit('updateGame', props.game, game.value);
	}
	// Adding game
	else {
		emit('addGame', game.value);
	}
}

/* Info Dialog */
const info_dialog = ref(false);
const info_dialog_text = ref('');

function openInfoDialog(text: string, event: Event) {
	// Stop expanding of the tree
	event.stopPropagation();

	info_dialog_text.value = text;
	info_dialog.value = true;
}

/* End Info Dialog */

/* Edit Goal Dialog */
interface EditGoalData {
	goal?: BingoGoal;
	all_tags: string[];
	reserved_names: string[];
	parent_group: BingoCategory | BingoGoalList | undefined;
}

const edit_goal_data = ref<EditGoalData>({
	all_tags: [] as string[],
	reserved_names: [] as string[],
	parent_group: undefined
});
const edit_goal_dialog = ref(false);
const openEditGoalDialog = (node: Node) => {
	edit_goal_data.value.goal = node.item as BingoGoal;
	edit_goal_data.value.reserved_names = game.value?.reserved_names ?? [];
	edit_goal_data.value.parent_group = node.parent;
	edit_goal_data.value.all_tags = game.value?.getAllTags() ?? [];
	edit_goal_dialog.value = true;
};

const create_goal = (goal: BingoGoal) => {
	// We always assume parent group is a goal list. You can't add goals to categories.
	const goal_list = edit_goal_data.value.parent_group as BingoGoalList;

	goal_list.goals.push(goal);

	// Reset values
	edit_goal_data.value = {
		goal: undefined,
		all_tags: [],
		reserved_names: [],
		parent_group: undefined
	};
	edit_goal_dialog.value = false;
};

const update_goal = (old_goal: BingoGoal, goal: BingoGoal) => {
	// We always assume parent group is a goal list. You can't add goals to categories.
	const goal_list = edit_goal_data.value.parent_group as BingoGoalList;

	const index = goal_list.goals.findIndex(g => g === old_goal);
	goal_list.goals.splice(index, 1, goal);

	// Reset values
	edit_goal_data.value = {
		goal: undefined,
		all_tags: [],
		reserved_names: [],
		parent_group: undefined
	};
	edit_goal_dialog.value = false;
};

const delete_goal = (goal: BingoGoal) => {
	// We always assume parent group is a goal list. You can't add goals to categories.
	const goal_list = edit_goal_data.value.parent_group as BingoGoalList;

	const index = goal_list.goals.findIndex(g => g === goal);
	goal_list.goals.splice(index, 1);

	// Reset values
	edit_goal_data.value = {
		goal: undefined,
		all_tags: [],
		reserved_names: [],
		parent_group: undefined
	};
	edit_goal_dialog.value = false;
};

/* End Edit Goal Dialog */

/* Edit Goal List Dialog */
interface EditGoalListData {
	goal_list?: BingoGoalList;
	reserved_names: string[];
	parent_group: BingoCategory | undefined;
}

const edit_goal_list_data = ref<EditGoalListData>({
	reserved_names: [] as string[],
	parent_group: undefined
});

const edit_goal_list_dialog = ref(false);

function openEditGoalListDialog(node: Node, event: Event) {
	// Stop expanding of the tree
	event.stopPropagation();

	edit_goal_list_data.value.goal_list = node.item as BingoGoalList;
	edit_goal_list_data.value.reserved_names = game.value?.reserved_names ?? [];
	edit_goal_list_data.value.parent_group = node.parent as BingoCategory;
	edit_goal_list_dialog.value = true;
}

const create_goal_list = (goal_list: BingoGoalList) => {
	// We always assume parent group is a category. You can't add goal lists to goal lists.
	const category = edit_goal_list_data.value.parent_group as BingoCategory;

	// Add goal list to category
	if (category) {
		category.goal_lists.push(goal_list);
	}
	// Add goal list to game
	else {
		game.value?.items.push(goal_list);
	}

	// Reset values
	edit_goal_list_data.value = {
		parent_group: undefined,
		reserved_names: []
	};
	edit_goal_list_dialog.value = false;
};

const update_goal_list = (old_goal_list: BingoGoalList, goal_list: BingoGoalList) => {
	// We always assume parent group is a category. You can't add goal lists to goal lists.
	const category = edit_goal_list_data.value.parent_group as BingoCategory;

	// Replace existing goal list in category
	if (category) {
		const index = category.goal_lists.findIndex(g => g === old_goal_list);
		category.goal_lists.splice(index, 1, goal_list);
	}
	// Replace existing goal list in game
	else {
		const index = game.value?.items.findIndex(g => g === old_goal_list);
		game.value?.items.splice(index, 1, goal_list);
	}

	// Reset values
	edit_goal_list_data.value = {
		parent_group: undefined,
		reserved_names: []
	};
	edit_goal_list_dialog.value = false;
};

const delete_goal_list = (goal_list: BingoGoalList) => {
	// Prevent deletion if goal list still has goals
	if (!goal_list.goals.length) {
		// We always assume parent group is a category. You can't add goal lists to goal lists.
		const category = edit_goal_list_data.value.parent_group as BingoCategory;

		// Delete goal list from category
		if (category) {
			const index = category.goal_lists.findIndex(g => g === goal_list);
			category.goal_lists.splice(index, 1);
		}
		// Delete goal list from game
		else {
			const index = game.value?.items.findIndex(g => g === goal_list);
			game.value?.items.splice(index, 1);
		}
	}

	// Reset values
	edit_goal_list_data.value = {
		parent_group: undefined,
		reserved_names: []
	};
	edit_goal_list_dialog.value = false;
};

/* End Edit Goal List Dialog */

/* Edit Category Dialog */

interface EditCategoryData {
	category?: BingoCategory;
}

const edit_category_data = ref<EditCategoryData>({
});

const edit_category_dialog = ref(false);

function openEditCategoryDialog(node: Node, event: Event) {
	// Stop expanding of the tree
	event.stopPropagation();

	edit_category_data.value.category = node.item as BingoCategory;
	edit_category_dialog.value = true;
}

const emit_category = (category: BingoCategory) => {
	// Add new category
	if (!edit_category_data.value.category) {
		game.value?.items.push(category);
	}
	// Replace existing category
	else {
		const index = game.value?.items.findIndex(g => g === category);
		game.value?.items.splice(index, 1, category);
	}

	// Reset values
	edit_category_data.value = {
	};
	edit_category_dialog.value = false;
};

const delete_category = (category: BingoCategory) => {
	const index = game.value?.items.findIndex(g => g === category);
	game.value?.items.splice(index, 1);

	// Reset values
	edit_category_data.value = {
	};
	edit_category_dialog.value = false;
};

/* End Edit Category Dialog */

const nodes = computed(() => {
	const results: Node[] = [];

	if (!game.value) {
		return results;
	}

	results.push(...game.value?.items.map(item => {
		const is_category = item instanceof BingoCategory;
		const is_goal_list = item instanceof BingoGoalList;

		const group_node: Node = {
			item,

			label: item.name,
			header: is_category
				? 'category'
				: is_goal_list
					? 'goal-list'
					: '',

			children: []
		};

		if (is_category) {
			group_node.children = item.goal_lists.map(goal_list => {
				const goal_list_node: Node = {
					item: goal_list,
					parent: item,

					label: goal_list.name,
					header: 'goal-list',

					children: []
				};

				goal_list_node.children?.push(...goal_list.goals.map(goal => {
					const goal_node: Node = {
						item: goal,
						parent: goal_list,

						label: goal.name,
						header: 'goal'
					};

					return goal_node;
				}));

				goal_list_node.children?.push({
					label: 'Add Goal',
					header: 'add-goal',
					parent: goal_list
				});

				return goal_list_node;
			});


			group_node.children?.push({
				label: 'Add Goal List',
				header: 'add-goal-list'
			});
		}
		else if (is_goal_list) {
			group_node.children = item.goals.map(goal => {
				const goal_node: Node = {
					item: goal,
					parent: item,

					label: goal.name,
					header: 'goal'
				};

				return goal_node;
			});

			group_node.children.push({
				label: 'Add Goal',
				header: 'add-goal',
				parent: item
			});
		}

		return group_node;
	}));

	results.push({
		label: 'Add Goal List',
		header: 'add-goal-list'
	});

	results.push({
		label: 'Add Category',
		header: 'add-category'
	});

	return results;
});
</script>

