<template>
	<div id="settings" class="window" role="tabpanel" aria-label="Settings">
		<div class="header">
			<SidebarToggle />
		</div>
		<form
			ref="settingsForm"
			class="container"
			autocomplete="off"
			@change="onChange"
			@submit.prevent
		>
			<h1 class="title">Settings</h1>

			<div>
				<label class="opt">
					<input
						:checked="$store.state.settings.advanced"
						type="checkbox"
						name="advanced"
					/>
					Advanced settings
				</label>
			</div>

			<div v-if="canRegisterProtocol || hasInstallPromptEvent">
				<h2>Native app</h2>
				<button
					v-if="hasInstallPromptEvent"
					type="button"
					class="btn"
					@click.prevent="nativeInstallPrompt"
				>
					Add The Lounge to Home screen
				</button>
				<button
					v-if="canRegisterProtocol"
					type="button"
					class="btn"
					@click.prevent="registerProtocol"
				>
					Open irc:// URLs with The Lounge
				</button>
			</div>

			<div v-if="!$store.state.serverConfiguration.public && $store.state.settings.advanced">
				<h2>Settings synchronisation</h2>
				<label class="opt">
					<input
						:checked="$store.state.settings.syncSettings"
						type="checkbox"
						name="syncSettings"
					/>
					Synchronize settings with other clients
				</label>
				<template v-if="!$store.state.settings.syncSettings">
					<div v-if="$store.state.serverHasSettings" class="settings-sync-panel">
						<p>
							<strong>Warning:</strong> Checking this box will override the settings
							of this client with those stored on the server.
						</p>
						<p>
							Use the button below to enable synchronization, and override any
							settings already synced to the server.
						</p>
						<button type="button" class="btn btn-small" @click="onForceSyncClick">
							Sync settings and enable
						</button>
					</div>
					<div v-else class="settings-sync-panel">
						<p>
							<strong>Warning:</strong> No settings have been synced before. Enabling
							this will sync all settings of this client as the base for other
							clients.
						</p>
					</div>
				</template>
			</div>

			<h2>Messages</h2>
			<div>
				<label class="opt">
					<input :checked="$store.state.settings.motd" type="checkbox" name="motd" />
					Show <abbr title="Message Of The Day">MOTD</abbr>
				</label>
			</div>
			<div>
				<label class="opt">
					<input
						:checked="$store.state.settings.showSeconds"
						type="checkbox"
						name="showSeconds"
					/>
					Include seconds in timestamp
				</label>
			</div>
			<div>
				<label class="opt">
					<input
						:checked="$store.state.settings.use12hClock"
						type="checkbox"
						name="use12hClock"
					/>
					Use 12-hour timestamps
				</label>
			</div>
			<div v-if="!$store.state.serverConfiguration.public && $store.state.settings.advanced">
				<h2>Automatic away message</h2>

				<label class="opt">
					<label for="awayMessage" class="sr-only">Automatic away message</label>
					<input
						id="awayMessage"
						:value="$store.state.settings.awayMessage"
						type="text"
						name="awayMessage"
						class="input"
						placeholder="Away message if The Lounge is not open"
					/>
				</label>
			</div>
			<h2 id="label-status-messages">
				Status messages
				<span
					class="tooltipped tooltipped-n tooltipped-no-delay"
					aria-label="Joins, parts, quits, kicks, nick changes, and mode changes"
				>
					<button class="extra-help" />
				</span>
			</h2>
			<div role="group" aria-labelledby="label-status-messages">
				<label class="opt">
					<input
						:checked="$store.state.settings.statusMessages === 'shown'"
						type="radio"
						name="statusMessages"
						value="shown"
					/>
					Show all status messages individually
				</label>
				<label class="opt">
					<input
						:checked="$store.state.settings.statusMessages === 'condensed'"
						type="radio"
						name="statusMessages"
						value="condensed"
					/>
					Condense status messages together
				</label>
				<label class="opt">
					<input
						:checked="$store.state.settings.statusMessages === 'hidden'"
						type="radio"
						name="statusMessages"
						value="hidden"
					/>
					Hide all status messages
				</label>
			</div>
			<h2>Visual Aids</h2>
			<div>
				<label class="opt">
					<input
						:checked="$store.state.settings.coloredNicks"
						type="checkbox"
						name="coloredNicks"
					/>
					Enable colored nicknames
				</label>
				<label class="opt">
					<input
						:checked="$store.state.settings.autocomplete"
						type="checkbox"
						name="autocomplete"
					/>
					Enable autocomplete
				</label>
			</div>
			<div v-if="$store.state.settings.advanced">
				<label class="opt">
					<label for="nickPostfix" class="opt">
						Nick autocomplete postfix
						<span
							class="tooltipped tooltipped-n tooltipped-no-delay"
							aria-label="Nick autocomplete postfix (for example a comma)"
						>
							<button class="extra-help" />
						</span>
					</label>
					<input
						id="nickPostfix"
						:value="$store.state.settings.nickPostfix"
						type="text"
						name="nickPostfix"
						class="input"
						placeholder="Nick autocomplete postfix (e.g. ', ')"
					/>
				</label>
			</div>

			<h2>Theme</h2>
			<div>
				<label for="theme-select" class="sr-only">Theme</label>
				<select
					id="theme-select"
					:value="$store.state.settings.theme"
					name="theme"
					class="input"
				>
					<option
						v-for="theme in $store.state.serverConfiguration.themes"
						:key="theme.name"
						:value="theme.name"
					>
						{{ theme.displayName }}
					</option>
				</select>
			</div>

			<template v-if="$store.state.serverConfiguration.prefetch">
				<h2>Link previews</h2>
				<div>
					<label class="opt">
						<input
							:checked="$store.state.settings.media"
							type="checkbox"
							name="media"
						/>
						Auto-expand media
					</label>
				</div>
				<div>
					<label class="opt">
						<input
							:checked="$store.state.settings.links"
							type="checkbox"
							name="links"
						/>
						Auto-expand websites
					</label>
				</div>
			</template>

			<div
				v-if="$store.state.settings.advanced && $store.state.serverConfiguration.fileUpload"
			>
				<h2>File uploads</h2>
				<div>
					<label class="opt">
						<input
							:checked="$store.state.settings.uploadCanvas"
							type="checkbox"
							name="uploadCanvas"
						/>
						Attempt to remove metadata from images before uploading
						<span
							class="tooltipped tooltipped-n tooltipped-no-delay"
							aria-label="This option renders the image into a canvas element to remove metadata from the image.
This may break orientation if your browser does not support that."
						>
							<button class="extra-help" />
						</span>
					</label>
				</div>
			</div>

			<template v-if="!$store.state.serverConfiguration.public">
				<h2>Push Notifications</h2>
				<div>
					<button
						id="pushNotifications"
						type="button"
						class="btn"
						:disabled="
							$store.state.pushNotificationState !== 'supported' &&
							$store.state.pushNotificationState !== 'subscribed'
						"
						@click="onPushButtonClick"
					>
						<template v-if="$store.state.pushNotificationState === 'subscribed'">
							Unsubscribe from push notifications
						</template>
						<template v-else-if="$store.state.pushNotificationState === 'loading'">
							Loading…
						</template>
						<template v-else> Subscribe to push notifications </template>
					</button>
					<div v-if="$store.state.pushNotificationState === 'nohttps'" class="error">
						<strong>Warning</strong>: Push notifications are only supported over HTTPS
						connections.
					</div>
					<div v-if="$store.state.pushNotificationState === 'unsupported'" class="error">
						<strong>Warning</strong>:
						<span>Push notifications are not supported by your browser.</span>

						<div v-if="isIOS" class="apple-push-unsupported">
							Safari does
							<a
								href="https://bugs.webkit.org/show_bug.cgi?id=182566"
								target="_blank"
								rel="noopener"
								>not support the web push notification specification</a
							>, and because all browsers on iOS use Safari under the hood, The Lounge
							is unable to provide push notifications on iOS devices.
						</div>
					</div>
				</div>
			</template>

			<h2>Browser Notifications</h2>
			<div>
				<label class="opt">
					<input
						id="desktopNotifications"
						:checked="$store.state.settings.desktopNotifications"
						:disabled="$store.state.desktopNotificationState === 'nohttps'"
						type="checkbox"
						name="desktopNotifications"
					/>
					Enable browser notifications<br />
					<div
						v-if="$store.state.desktopNotificationState === 'unsupported'"
						class="error"
					>
						<strong>Warning</strong>: Notifications are not supported by your browser.
					</div>
					<div
						v-if="$store.state.desktopNotificationState === 'nohttps'"
						id="warnBlockedDesktopNotifications"
						class="error"
					>
						<strong>Warning</strong>: Notifications are only supported over HTTPS
						connections.
					</div>
					<div
						v-if="$store.state.desktopNotificationState === 'blocked'"
						id="warnBlockedDesktopNotifications"
						class="error"
					>
						<strong>Warning</strong>: Notifications are blocked by your browser.
					</div>
				</label>
			</div>
			<div>
				<label class="opt">
					<input
						:checked="$store.state.settings.notification"
						type="checkbox"
						name="notification"
					/>
					Enable notification sound
				</label>
			</div>
			<div>
				<div class="opt">
					<button id="play" @click.prevent="playNotification">Play sound</button>
				</div>
			</div>

			<div v-if="$store.state.settings.advanced">
				<label class="opt">
					<input
						:checked="$store.state.settings.notifyAllMessages"
						type="checkbox"
						name="notifyAllMessages"
					/>
					Enable notification for all messages
				</label>
			</div>

			<div v-if="!$store.state.serverConfiguration.public && $store.state.settings.advanced">
				<label class="opt">
					<label for="highlights" class="opt">
						Custom highlights
						<span
							class="tooltipped tooltipped-n tooltipped-no-delay"
							aria-label="If a message contains any of these comma-separated 
expressions, it will trigger a highlight."
						>
							<button class="extra-help" />
						</span>
					</label>
					<input
						id="highlights"
						:value="$store.state.settings.highlights"
						type="text"
						name="highlights"
						class="input"
						placeholder="Comma-separated, e.g.: word, some more words, anotherword"
					/>
				</label>
			</div>

			<div v-if="!$store.state.serverConfiguration.public && $store.state.settings.advanced">
				<label class="opt">
					<label for="highlightExceptions" class="opt">
						Highlight exceptions
						<span
							class="tooltipped tooltipped-n tooltipped-no-delay"
							aria-label="If a message contains any of these comma-separated 
expressions, it will not trigger a highlight even if it contains 
your nickname or expressions defined in custom highlights."
						>
							<button class="extra-help" />
						</span>
					</label>
					<input
						id="highlightExceptions"
						:value="$store.state.settings.highlightExceptions"
						type="text"
						name="highlightExceptions"
						class="input"
						placeholder="Comma-separated, e.g.: word, some more words, anotherword"
					/>
				</label>
			</div>

			<div
				v-if="
					!$store.state.serverConfiguration.public &&
					!$store.state.serverConfiguration.ldapEnabled
				"
				id="change-password"
				role="group"
				aria-labelledby="label-change-password"
			>
				<h2 id="label-change-password">Change password</h2>
				<div class="password-container">
					<label for="current-password" class="sr-only"> Enter current password </label>
					<RevealPassword v-slot:default="slotProps">
						<input
							id="current-password"
							autocomplete="current-password"
							:type="slotProps.isVisible ? 'text' : 'password'"
							name="old_password"
							class="input"
							placeholder="Enter current password"
						/>
					</RevealPassword>
				</div>
				<div class="password-container">
					<label for="new-password" class="sr-only"> Enter desired new password </label>
					<RevealPassword v-slot:default="slotProps">
						<input
							id="new-password"
							:type="slotProps.isVisible ? 'text' : 'password'"
							name="new_password"
							autocomplete="new-password"
							class="input"
							placeholder="Enter desired new password"
						/>
					</RevealPassword>
				</div>
				<div class="password-container">
					<label for="new-password-verify" class="sr-only"> Repeat new password </label>
					<RevealPassword v-slot:default="slotProps">
						<input
							id="new-password-verify"
							:type="slotProps.isVisible ? 'text' : 'password'"
							name="verify_password"
							autocomplete="new-password"
							class="input"
							placeholder="Repeat new password"
						/>
					</RevealPassword>
				</div>
				<div
					v-if="passwordChangeStatus && passwordChangeStatus.success"
					class="feedback success"
				>
					Successfully updated your password
				</div>
				<div
					v-else-if="passwordChangeStatus && passwordChangeStatus.error"
					class="feedback error"
				>
					{{ passwordErrors[passwordChangeStatus.error] }}
				</div>
				<div>
					<button type="submit" class="btn" @click.prevent="changePassword">
						Change password
					</button>
				</div>
			</div>

			<div v-if="$store.state.settings.advanced">
				<h2>Custom Stylesheet</h2>
				<label for="user-specified-css-input" class="sr-only">
					Custom stylesheet. You can override any style with CSS here.
				</label>
				<textarea
					id="user-specified-css-input"
					:value="$store.state.settings.userStyles"
					class="input"
					name="userStyles"
					placeholder="/* You can override any style with CSS here */"
				/>
			</div>

			<div v-if="!$store.state.serverConfiguration.public" class="session-list" role="group">
				<h2>Sessions</h2>

				<h3>Current session</h3>
				<Session v-if="currentSession" :session="currentSession" />

				<template v-if="activeSessions.length > 0">
					<h3>Active sessions</h3>
					<Session
						v-for="session in activeSessions"
						:key="session.token"
						:session="session"
					/>
				</template>

				<h3>Other sessions</h3>
				<p v-if="$store.state.sessions.length === 0">Loading…</p>
				<p v-else-if="otherSessions.length === 0">
					<em>You are not currently logged in to any other device.</em>
				</p>
				<Session
					v-for="session in otherSessions"
					v-else
					:key="session.token"
					:session="session"
				/>
			</div>
		</form>
	</div>
</template>

<style>
textarea#user-specified-css-input {
	height: 100px;
}
</style>

<script>
import socket from "../../js/socket";
import webpush from "../../js/webpush";
import RevealPassword from "../RevealPassword.vue";
import Session from "../Session.vue";
import SidebarToggle from "../SidebarToggle.vue";

let installPromptEvent = null;

window.addEventListener("beforeinstallprompt", (e) => {
	e.preventDefault();
	installPromptEvent = e;
});

export default {
	name: "Settings",
	components: {
		RevealPassword,
		Session,
		SidebarToggle,
	},
	data() {
		return {
			canRegisterProtocol: false,
			passwordChangeStatus: null,
			passwordErrors: {
				missing_fields: "Please enter a new password",
				password_mismatch: "Both new password fields must match",
				password_incorrect:
					"The current password field does not match your account password",
				update_failed: "Failed to update your password",
			},
			isIOS: navigator.platform.match(/(iPhone|iPod|iPad)/i) || false,
		};
	},
	computed: {
		hasInstallPromptEvent() {
			// TODO: This doesn't hide the button after clicking
			return installPromptEvent !== null;
		},
		currentSession() {
			return this.$store.state.sessions.find((item) => item.current);
		},
		activeSessions() {
			return this.$store.state.sessions.filter((item) => !item.current && item.active > 0);
		},
		otherSessions() {
			return this.$store.state.sessions.filter((item) => !item.current && !item.active);
		},
	},
	mounted() {
		socket.emit("sessions:get");

		// Enable protocol handler registration if supported,
		// and the network configuration is not locked
		this.canRegisterProtocol =
			window.navigator.registerProtocolHandler &&
			!this.$store.state.serverConfiguration.lockNetwork;
	},
	methods: {
		onChange(event) {
			const ignore = ["old_password", "new_password", "verify_password"];

			const name = event.target.name;

			if (ignore.includes(name)) {
				return;
			}

			let value;

			if (event.target.type === "checkbox") {
				value = event.target.checked;
			} else {
				value = event.target.value;
			}

			this.$store.dispatch("settings/update", {name, value, sync: true});
		},
		changePassword() {
			const allFields = new FormData(this.$refs.settingsForm);
			const data = {
				old_password: allFields.get("old_password"),
				new_password: allFields.get("new_password"),
				verify_password: allFields.get("verify_password"),
			};

			if (!data.old_password || !data.new_password || !data.verify_password) {
				this.passwordChangeStatus = {
					success: false,
					error: "missing_fields",
				};
				return;
			}

			if (data.new_password !== data.verify_password) {
				this.passwordChangeStatus = {
					success: false,
					error: "password_mismatch",
				};
				return;
			}

			socket.once("change-password", (response) => {
				this.passwordChangeStatus = response;
			});

			socket.emit("change-password", data);
		},
		onForceSyncClick() {
			this.$store.dispatch("settings/syncAll", true);
			this.$store.dispatch("settings/update", {
				name: "syncSettings",
				value: true,
				sync: true,
			});
		},
		registerProtocol() {
			const uri = document.location.origin + document.location.pathname + "?uri=%s";

			window.navigator.registerProtocolHandler("irc", uri, "The Lounge");
			window.navigator.registerProtocolHandler("ircs", uri, "The Lounge");
		},
		nativeInstallPrompt() {
			installPromptEvent.prompt();
			installPromptEvent = null;
		},
		playNotification() {
			const pop = new Audio();
			pop.src = "audio/pop.wav";
			pop.play();
		},
		onPushButtonClick() {
			webpush.togglePushSubscription();
		},
	},
};
</script>