<template>
	<div v-if="$i && fetching" class="">
		<MkLoading />
	</div>
	<div v-else-if="$i">
		<XForm
			v-if="state == 'waiting'"
			ref="form"
			class="form"
			:session="session"
			@denied="state = 'denied'"
			@accepted="accepted"
		/>
		<div v-if="state == 'denied'" class="denied">
			<h1>{{ i18n.ts._auth.denied }}</h1>
		</div>
		<div v-if="state == 'accepted'" class="accepted">
			<h1>
				{{
					session.app.isAuthorized
						? i18n.t("already-authorized")
						: i18n.ts.allowed
				}}
			</h1>
			<p v-if="session.app.callbackUrl && !auth_code">
				{{ i18n.ts._auth.callback }}<MkEllipsis />
			</p>
			<MkKeyValue
				v-if="session.app.callbackUrl && auth_code"
				:copy="auth_code"
			>
				<template #key>{{ i18n.ts._auth.copyAsk }}</template>
				<template #value>{{ auth_code }}</template>
			</MkKeyValue>
			<p v-if="!session.app.callbackUrl">
				{{ i18n.ts._auth.pleaseGoBack }}
			</p>
		</div>
		<div v-if="state == 'fetch-session-error'" class="error">
			<p>{{ i18n.ts.somethingHappened }}</p>
		</div>
	</div>
	<div v-else class="signin">
		<MkSignin @login="onLogin" />
	</div>
</template>

<script lang="ts">
import { defineComponent } from "vue";
import XForm from "./auth.form.vue";
import MkSignin from "@/components/MkSignin.vue";
import MkKeyValue from "@/components/MkKeyValue.vue";
import * as os from "@/os";
import { login } from "@/account";
import { i18n } from "@/i18n";

export default defineComponent({
	components: {
		XForm,
		MkSignin,
		MkKeyValue,
	},
	props: ["token"],
	data() {
		return {
			state: null,
			session: null,
			fetching: true,
			i18n,
			auth_code: null,
		};
	},
	mounted() {
		if (!this.$i) return;

		// Fetch session
		os.api("auth/session/show", {
			token: this.token,
		})
			.then((session) => {
				this.session = session;
				this.fetching = false;

				// 既に連携していた場合
				if (this.session.app.isAuthorized) {
					os.api("auth/accept", {
						token: this.session.token,
					}).then(() => {
						this.accepted();
					});
				} else {
					this.state = "waiting";
				}
			})
			.catch((error) => {
				this.state = "fetch-session-error";
				this.fetching = false;
			});
	},
	methods: {
		accepted() {
			this.state = "accepted";
			const getUrlParams = () =>
				window.location.search
					.substring(1)
					.split("&")
					.reduce((result, query) => {
						const [k, v] = query.split("=");
						result[k] = decodeURIComponent(v);
						return result;
					}, {});
			const isMastodon = !!getUrlParams().mastodon;
			if (this.session.app.callbackUrl && isMastodon) {
				const redirectUri = getUrlParams().redirect_uri;
				if (!this.session.app.callbackUrl.split('\n').some(p => p === redirectUri)){
					this.state = "fetch-session-error";
					this.fetching = false;
					console.log(`redirect uri: ${redirectUri}`);
					console.log(`reg_app uris: ${this.session.app.callbackUrl.split('\n').join(',')}`);
					throw new Error("callback uri doesn't match registered app");
				}
				const callbackUrl = new URL(redirectUri)
				callbackUrl.searchParams.append("code", this.session.token);
				if (!!getUrlParams().state)
					callbackUrl.searchParams.append(
						"state",
						getUrlParams().state,
					);
				location.href = callbackUrl.toString();
			} else if (this.session.app.callbackUrl) {
				const url = new URL(this.session.app.callbackUrl);
				if (
					[
						"javascript:",
						"file:",
						"data:",
						"mailto:",
						"tel:",
					].includes(url.protocol)
				)
					throw new Error("invalid url");
				if (
					this.session.app.callbackUrl === "urn:ietf:wg:oauth:2.0:oob"
				) {
					this.auth_code = this.session.token;
				} else {
					location.href = `${this.session.app.callbackUrl}?token=${
						this.session.token
					}&code=${this.session.token}&state=${
						getUrlParams().state || ""
					}`;
				}
			}
		},
		onLogin(res) {
			login(res.i);
		},
	},
});
</script>

<style lang="scss" scoped></style>
