<script lang="ts" context="module">
	export type Model = {
		id: string;
		name: string;
		color_mode: string;
		width: number;
		height: number;
		status: number;
		model_type: number;
		format: string;
	};

	export type Layer = {
		layer_type: number;
		shape: string;
	};

	export type Definitions = {
		epoch: number;
		epoch_progress: number;
		status: number;
		accuracy: number;
		layers?: Layer[];
	};
</script>

<script lang="ts">
	import { onMount } from 'svelte';

	import BaseModelInfo from './BaseModelInfo.svelte';
	import DeleteModel from './DeleteModel.svelte';
	import { goto } from '$app/navigation';
	import { get, rdelete } from 'src/lib/requests.svelte';
	import MessageSimple from '$lib/MessageSimple.svelte';

	import ModelData from './ModelData.svelte';
	import DeleteZip from './DeleteZip.svelte';
	import RunModel from './RunModel.svelte';

	import Tabs from 'src/lib/Tabs.svelte';
	import TasksDataPage from './TasksDataPage.svelte';
	import ModelDataPage from './ModelDataPage.svelte';

	import 'src/styles/forms.css';
	import KeepPageSize from 'src/lib/KeepPageSize.svelte';

	let model: Promise<Model> = $state(new Promise(() => {}));
	let _model: Model | undefined = $state(undefined);
	let definitions: Promise<Definitions[]> = $state(new Promise(() => {}));

	let id: string | undefined = $state();

	async function getModel() {
		try {
			let temp_model: Model = await get(`models/edit?id=${id}`);

			if ([3, 6].includes(temp_model.status)) {
				setTimeout(getModel, 2000);
			}

			if (temp_model.status == 4) {
				setTimeout(getModel, 5000);

				definitions = await get(`models/edit/definitions?id=${id}`);
			}

			model = Promise.resolve(temp_model);
			_model = temp_model;
		} catch (e) {
			if (e instanceof Response) {
				model = Promise.reject(await e.json());
			} else {
				model = Promise.reject('Could not load model');
			}
		}
	}

	onMount(() => {
		let url = new URLSearchParams(window.location.search);
		const _id = url.get('id');
		if (!_id) {
			goto('/models');
			return;
		}

		id = _id;
		getModel();
	});

	let resetMessages: MessageSimple;
	async function resetModel() {
		resetMessages.display('');

		let _model = await model;

		try {
			await rdelete('models/train/reset', {
				id: _model.id
			});

			getModel();
		} catch (e) {
			if (e instanceof Response) {
				resetMessages.display(await e.json());
			} else {
				resetMessages.display('Could not reset model!');
			}
		}
	}

	// Auto reload after 2s when model.status 3,4
</script>

<svelte:head>
	{#await model}
		<title>Model</title>
	{:then m}
		{#if m}
			<title>
				Model: {m.name}
			</title>
		{:else}
			<title>Model</title>
		{/if}
	{/await}
</svelte:head>

<KeepPageSize />

<main>
	{#if [4, 7].includes(_model?.status ?? 0)}
		<div class="big-msg warning">The Model is currently training</div>
	{/if}
	{#if [-4, -7].includes(_model?.status ?? 0)}
		<div class="big-msg danger">The Model is failed to train</div>
	{/if}
	<Tabs active="model" let:isActive nobox>
		<div slot="buttons" let:setActive let:isActive>
			<button
				class="tab"
				on:click|preventDefault={setActive('model')}
				class:selected={isActive('model')}
			>
				Model
			</button>
			{#if _model && [2, 3, 4, 5, 6, 7].includes(_model.status)}
				<button
					class="tab"
					on:click|preventDefault={setActive('model-data')}
					class:selected={isActive('model-data')}
				>
					Model Data
				</button>
			{/if}
			{#if _model && [5, 6, 7].includes(_model.status)}
				<button
					class="tab"
					on:click|preventDefault={setActive('tasks')}
					class:selected={isActive('tasks')}
				>
					Tasks
				</button>
			{/if}
		</div>
		{#if _model}
			<ModelDataPage model={_model} on:reload={getModel} active={isActive('model-data')} />
			<TasksDataPage model={_model} active={isActive('tasks')} />
		{/if}
		<div class="content" class:selected={isActive('model')}>
			{#await model}
				Loading
			{:then m}
				{#if m.status == 1}
					<div>
						<h1 class="text-center">
							{m.name}
						</h1>
						<!-- TODO add cool animation -->
						<h2 class="text-center">Preparing the model</h2>
					</div>
				{:else if m.status == -1}
					<div>
						<h1 class="text-center">
							{m.name}
						</h1>
						<!-- TODO improve message -->
						<h2 class="text-center">Failed to prepare model</h2>

						<DeleteModel model={m} />
					</div>
					<!-- PRE TRAINING STATUS -->
				{:else if m.status == 2}
					<BaseModelInfo model={m} />
					<ModelData model={m} on:reload={getModel} />
					<!-- {{ template "train-model-card" . }} -->
					<DeleteModel model={m} />
				{:else if m.status == -2}
					<BaseModelInfo model={m} />
					<DeleteZip model={m} on:reload={getModel} />
					<DeleteModel model={m} />
				{:else if m.status == 3}
					<BaseModelInfo model={m} />
					<div class="card">
						<!-- TODO improve this -->
						Processing zip file...
					</div>
				{:else if m.status == -3 || m.status == -4}
					<BaseModelInfo model={m} />
					<form on:submit={resetModel}>
						Failed Prepare for training.<br />
						<div class="spacer"></div>
						<MessageSimple bind:this={resetMessages} />
						<button class="danger"> Try Again </button>
					</form>
					<DeleteModel model={m} />
				{:else if m.status == 4}
					<BaseModelInfo model={m} />
					<!-- TODO request /models/edit?id={m.id} -->
					<div class="card">
						<!-- TODO improve this -->
						Training the model...<br />
						<!-- TODO Add progress status on definitions -->
						{#await definitions}
							Loading
						{:then defs}
							<table>
								<thead>
									<tr>
										<th> Done Progress </th>
										<th> Training Round Progress </th>
										<th> Accuracy </th>
										<th> Status </th>
									</tr>
								</thead>
								<tbody>
									{#each defs as def}
										<tr>
											<td>
												{def.epoch}
											</td>
											<td>
												{def.epoch_progress}/20
											</td>
											<td>
												{def.accuracy}%
											</td>
											<td style="text-align: center;">
												{#if def.status == 2}
													<span class="bi bi-book" style="color: green;"></span>
												{:else if [3, 6, -3].includes(def.status)}
													<span
														class="bi bi-book-half"
														style="color: {{
															'3': 'green',
															'-3': 'red',
															'6': 'orange'
														}[String(def.status)]};"
													></span>
												{:else}
													{def.status}
												{/if}
											</td>
										</tr>
										{#if def.status == 3 && def.layers}
											<tr>
												<td colspan="4">
													<svg viewBox="0 200 1000 600">
														{#each def.layers as layer, i}
															{@const sep_mod =
																def.layers.length > 8
																	? Math.max(10, 100 - (def.layers.length - 8) * 10)
																	: 100}
															{#if layer.layer_type == 1}
																<polygon
																	points="50,450 200,250 200,550 50,750"
																	stroke="black"
																	stroke-width="2"
																	fill="green"
																></polygon>
															{:else if layer.layer_type == 4}
																<polygon
																	points="{50 + i * sep_mod},450 {200 + i * sep_mod},250 {200 +
																		i * sep_mod},550 {50 + i * sep_mod},750"
																	stroke="black"
																	stroke-width="2"
																	fill="orange"
																>
																</polygon>
															{:else if layer.layer_type == 3}
																<polygon
																	points="{50 + i * sep_mod},450 {200 + i * sep_mod},250 {200 +
																		i * sep_mod},550 {50 + i * sep_mod},750"
																	stroke="black"
																	stroke-width="2"
																	fill="red"
																>
																</polygon>
															{:else if layer.layer_type == 2}
																<polygon
																	points="{50 + i * sep_mod},550 {200 + i * sep_mod},350 {200 +
																		i * sep_mod},450 {50 + i * sep_mod},650"
																	stroke="black"
																	stroke-width="2"
																	fill="blue"
																>
																</polygon>
															{:else}
																<div>
																	{layer.layer_type}
																	{layer.shape}
																</div>
															{/if}
														{/each}
													</svg>
												</td>
											</tr>
										{/if}
									{/each}
								</tbody>
							</table>
						{/await}
						<!-- TODO Add ability to stop training -->
					</div>
				{:else if [5, 6, -6, 7, -7].includes(m.status)}
					<BaseModelInfo model={m} />
					<RunModel model={m} />
					{#if m.status == 6}
						<div class="card">Model expading... Processing ZIP file</div>
					{/if}
					{#if m.status == -6}
						<DeleteZip model={m} on:reload={getModel} expand />
					{/if}
					{#if m.status == -7}
						<form>
							<!-- TODO add more info about the failure -->
							Failed to train the model! Try to retrain
						</form>
					{/if}
					{#if m.model_type == 2}
						<ModelData simple model={m} on:reload={getModel} />
					{/if}
					<DeleteModel model={m} />
				{:else}
					<h1>Unknown Status of the model.</h1>
				{/if}
			{/await}
		</div>
	</Tabs>
</main>

<style lang="scss">
	main {
		padding: 20px 15vw;
	}
	table {
		width: 100%;
		box-shadow: 0 2px 8px 1px #66666622;
		border-radius: 10px;
		border-collapse: collapse;
		overflow: hidden;
	}

	table thead {
		background: #60606022;
	}

	table tr td,
	table tr th {
		border-left: 1px solid #22222244;
		padding: 15px;
	}

	table tr td:first-child,
	table tr th:first-child {
		border-left: none;
	}

	table tr td button,
	table tr td .button {
		padding: 5px 10px;
		box-shadow: 0 2px 5px 1px #66666655;
	}
</style>
