<template>
	<div class="w-full sm:max-w-sm sm:mx-auto sm:my-auto p-6 space-y-4 bg-white rounded-lg shadow-md">
		<div class="text-center font-thin text-4xl py-4">AUTOPLEX</div>
		<div class="font-medium text-center text-xl">Sign Up</div>
		<form @submit.prevent="register">
			<div class="space-y-4">
				<div>
					<text-box label="Access Token" type="text" disabled
					v-model="fields.token" :validator="validateToken" ref="token"/>
				</div>
				<div>
					<text-box label="Your Name" type="text" placeholder="John Doe" :disabled="isSubmitting"
					v-model="fields.name" :validator="constraints.name" ref="name"/>
				</div>
				<div>
					<text-box label="Email" type="email" placeholder="john@example.com" :disabled="isSubmitting"
					v-model="fields.email" :validator="validateEmail" ref="email"/>
				</div>
				<div>
					<text-box label="Password" type="password" placeholder="············" :disabled="isSubmitting"
					v-model="fields.password" :validator="constraints.password" ref="password"
					/>
				</div>
				<div>
					<text-box label="Re-type Password" type="password" placeholder="············" :disabled="isSubmitting"
					v-model="fields.retypePassword" :validator="validateRetypePassword" ref="retypePassword"/>
				</div>
				<div>
					<button type="submit" class="block w-full rounded-full bg-indigo-500 text-white p-3 focus:outline-none" :disabled="isSubmitting">Register</button>
				</div>
			</div>
		</form>
	</div>
</template>

<script lang="ts">
import { defineComponent, reactive } from "vue";
import CheckBox from "../components/CheckBox.vue";
import TextBox from "../components/TextBox.vue";
import { constraints } from "../../common/validation";
import { validateValue } from "../util";

export default defineComponent({
	components: {
		CheckBox,
		TextBox
	},
	data() {
		return {
			isSubmitting  : false,
			fields: reactive({
				token         : <string>this.$route.query["token"],
				name          : "",
				email         : "",
				password      : "",
				retypePassword: "",
			}),
			constraints: {
				name: constraints.register.name,
				email: constraints.register.email,
				password: constraints.register.password
			}
		}
	},
	methods: {
		/**
		 * Submit the registration form
		 */
		async register() {
			if (this.isSubmitting) {
				return;
			}
			this.isSubmitting = true;
			fetch(`/auth/register`, {
				method: "post",
				headers: {
					"Content-Type": "application/json"
				},
				body: JSON.stringify(this.fields)
			})
			.then(async response => {
				this.isSubmitting = false;
				if (response.status !== 200) {
					let body = await response.json();
					if (body.errors) {
						for (let fieldName in this.fields) {
							let field = <any>this.$refs[fieldName];
							let message = <string>(body.errors[fieldName] ?? [""])[0];
							field.setErrorMessage(message);
						}
					}
					return;
				}
				this.$router.push({ name: "Login" });
			})
			.catch(e => {
				console.error("Error occurred during submission:", e);
				this.isSubmitting = false;
			});
		},

		/**
		 * Validate the provided registration token
		 */
		async validateToken(token: string) {
			let response = await fetch(`/auth/register/validate_token/${token}`, { method: "post" });
			if (response.status !== 200) {
				return "A valid token is required to register";
			}
		},

		/**
		 * Validate the provided email address field
		 */
		async validateEmail(email: string) {
			let error = validateValue(email, constraints.register.email);
			if (error) {
				return error;
			}
			// Check email availability
			let response = await fetch(`/auth/register/available_email/${email}`, { method: "post" });
			if (response.status !== 200) {
				return "An account with that email address already exists";
			}
		},

		/**
		 * Validate the provided retype-password field
		 */
		validateRetypePassword(value: string) {
			if (value.trim().length == 0) {
				return constraints.register.retypePassword.presence.message;
			}
			if (value !== this.fields.password) {
				return constraints.register.retypePassword.equality.message;
			}
		}
	},
	/**
	 * Navigation Guard
	 */
	beforeRouteEnter(to, from, next) {
		if (to.query["token"] === undefined) {
			next({ name: "Login" });
		} else {
			next();
		}
	}
});
</script>

<style lang="postcss">
	button:focus-visible {
		@apply ring-2 ring-indigo-500 ring-offset-2;
	}
</style>
