<script setup>
import { format } from 'date-fns';
import { computed, inject, ref, useId } from 'vue';

import EditActors from '#/components/edit/actors.vue';
import EditMovies from '#/components/edit/movies.vue';
import EditTags from '#/components/edit/tags.vue';
import Checkbox from '#/components/form/checkbox.vue';

import { post } from '#/src/api.js';
import verifyAbility from '#/utils/verify-ability.js';

const pageContext = inject('pageContext');

const user = pageContext.user;
const scene = ref(pageContext.pageProps.scene);
const applyTooltipId = useId();

const fields = computed(() => [
	{
		key: 'actors',
		type: 'actors',
		value: scene.value.actors,
	},
	{
		key: 'tags',
		type: 'tags',
		value: scene.value.tags.toSorted((tagA, tagB) => tagA.name.localeCompare(tagB.name)),
		simplify: false,
		note: 'Actor-specific tags should only be used where confusion is reasonable, such as group scenes in which some perform anal, and some don\'t.',
	},
	{
		key: 'url',
		label: 'URL',
		type: 'string',
		value: scene.value.url,
		enabled: verifyAbility(user, 'scene', 'update'),
	},
	{
		key: 'title',
		type: 'string',
		value: scene.value.title,
		note: 'Do not correct language errors unless source was updated.',
	},
	{
		key: 'description',
		type: 'text',
		value: scene.value.description,
		note: 'Do not correct language errors unless source was updated.',
	},
	{
		key: 'date',
		type: 'date',
		value: {
			date: scene.value.date
				? format(scene.value.date, 'yyyy-MM-dd hh:mm')
				: null,
			precision: scene.value.datePrecision,
		},
	},
	{
		key: 'duration',
		type: 'duration',
		value: [Math.floor(scene.value.duration / 3600), Math.floor((scene.value.duration % 3600) / 60), scene.value.duration % 60],
		simplify: false,
	},
	{
		key: 'productionDate',
		label: 'production date',
		type: 'date',
		value: {
			date: scene.value.productionDate
				? format(scene.value.productionDate, 'yyyy-MM-dd hh:mm')
				: null,
			precision: scene.value.productionDatePrecision, // not currently implemented
		},
	},
	{
		key: 'movies',
		type: 'movies',
		value: scene.value.movies,
	},
	{
		key: 'comment',
		type: 'text',
		placeholder: 'Do NOT use this field to summarize and clarify your revision. This field is for permanent notes and comments regarding the scene or database entry itself.',
		value: scene.value.comment,
		enabled: verifyAbility(user, 'scene', 'update'),
	},
	{
		key: 'delete',
		type: 'checkbox',
		checkboxLabel: 'Remove this scene from the database',
		value: false,
		enabled: verifyAbility(user, 'scene', 'delete'),
	},
].filter((field) => field.enabled !== false));

function simplifyArray(field) {
	if (Array.isArray(field.value) && field.simplify !== false) {
		return field.value.map((item) => item.hash || item.id);
	}

	return field.value;
}

const editing = ref(new Set());
const edits = ref(Object.fromEntries(fields.value.map((field) => [field.key, simplifyArray(field)])));
const comment = ref(null);
const apply = ref(user.role !== 'user');
const submitted = ref(false);

const userCanDelete = user.abilities.some((ability) => ability.subject === 'scene' && ability.action === 'delete');
const isApplyDisabled = computed(() => editing.value.size === 0 || (edits.value.delete && !userCanDelete));

const keyMap = {
	date: {
		date: 'date',
		precision: 'datePrecision',
	},
	productionDate: {
		date: 'productionDate',
		precision: 'productionDatePrecision',
	},
};

function toggleField(item) {
	if (editing.value.has(item.key)) {
		editing.value.delete(item.key);

		return;
	}

	editing.value.add(item.key);
}

const timeUnits = ['h', 'm', 's'];

function setDuration(unit, event) {
	edits.value.duration[timeUnits.indexOf(unit)] = Number(event.target.value);
}

function setDelete(checked) {
	edits.value.delete = checked;

	if (!userCanDelete) {
		apply.value = false;
	}
}

async function submit() {
	try {
		await post('/revisions/scenes', {
			sceneId: scene.value.id,
			edits: {
				...Object.fromEntries(Array.from(editing.value).flatMap((key) => {
					if (edits.value[key] && typeof edits.value[key] === 'object' && !Array.isArray(edits.value[key])) {
						return Object.entries(edits.value[key]).map(([valueKey, value]) => [keyMap[key]?.[valueKey] || valueKey, value]);
					}

					return [[key, edits.value[key]]];
				})),
				// duration: edits.value.duration
				duration: editing.value.has('duration') && edits.value.duration
					? (((edits.value.duration[0] || 0) * 3600) + ((edits.value.duration[1] || 0) * 60) + (edits.value.duration[2] || 0)) || null
					: undefined,
			},
			comment: comment.value,
			apply: apply.value,
		}, {
			successFeedback: 'Your revision has been submitted for approval.',
			appendErrorMessage: true,
		});

		editing.value = new Set();
		edits.value = {};
		comment.value = null;

		submitted.value = true;

		// scene.value = await get(`/scenes/${scene.value.id}`);
	}
	catch (error) {
		// do nothing
	}
}
</script>

<template>
	<div class="editor">
		<p
			v-if="submitted"
			class="submitted"
		>
			<template v-if="apply">Your revision has been submitted. Thank you for your contribution!</template>
			<template v-else>Your revision has been submitted for review. Thank you for your contribution!</template>

			<ul>
				<li>
					<a
						:href="`/scene/${scene.id}/${scene.slug}`"
						class="link"
					>Return to scene</a>
				</li>

				<li>
					<a
						:href="`/scene/edit/${scene.id}`"
						class="link"
					>Make another edit</a>
				</li>

				<li>
					<a
						:href="`/scene/revs/${scene.id}/${scene.slug}`"
						class="link"
					>Go to scene revisions</a>
				</li>

				<li>
					<a
						:href="`/user/${user.username}/revisions/scenes`"
						class="link"
					>Go to user revisions</a>
				</li>

				<li v-if="user.role !== 'user'">
					<a
						href="/admin/revisions/scenes"
						class="link"
					>Go to revisions admin</a>
				</li>
			</ul>
		</p>

		<form
			v-else
			@submit.prevent
		>
			<div class="editor-header">
				<h2 class="heading ellipsis">Edit scene #{{ scene.id }} - {{ scene.title }}</h2>

				<a
					:href="`/scene/${scene.id}/${scene.slug}`"
					target="_blank"
					class="link noshrink"
				>Go to scene</a>
			</div>

			<ul class="nolist">
				<li
					v-for="item in fields"
					:key="`item-${item.key}`"
					class="row"
				>
					<div class="item-header">
						<div class="key">
							{{ item.label || item.key }}

							<Icon
								v-if="item.note"
								v-tooltip="{ content: item.note, ariaId: `field-note-${item.key}` }"
								icon="info2"
								class="item-note noselect"
							/>
						</div>

						<div class="item-actions">
							<Icon
								v-if="!item.forced"
								icon="pencil5"
								class="noselect"
								:class="{ active: editing.has(item.key) }"
								@click="toggleField(item)"
							/>
						</div>
					</div>

					<div
						class="value"
						:class="{ disabled: !editing.has(item.key) }"
					>
						<EditActors
							v-if="item.type === 'actors'"
							:scene="scene"
							:item="item"
							:edits="edits"
							:editing="editing"
							@actors="(actors) => { edits.actors = actors; }"
						/>

						<EditTags
							v-if="item.type === 'tags'"
							:scene="scene"
							:item="item"
							:edits="edits"
							:editing="editing"
							@tags="(tags) => { edits.tags = tags; }"
						/>

						<EditMovies
							v-if="item.type === 'movies'"
							:scene="scene"
							:item="item"
							:edits="edits"
							:editing="editing"
							@movies="(movies) => { edits.movies = movies; }"
						/>

						<input
							v-if="item.type === 'string'"
							v-model="edits[item.key]"
							class="string input"
							:disabled="!editing.has(item.key)"
						>

						<textarea
							v-if="item.type === 'text'"
							v-model="edits[item.key]"
							:placeholder="item.placeholder"
							rows="3"
							class="text input"
							:disabled="!editing.has(item.key)"
						/>

						<Checkbox
							v-if="item.type === 'checkbox'"
							:label="item.checkboxLabel"
							:checked="edits[item.key]"
							:disabled="!editing.has(item.key)"
							class="checkbox delete"
							@change="(checked) => setDelete(checked)"
						/>

						<div
							v-if="item.type === 'date'"
							class="date"
						>
							<input
								v-model="edits[item.key].date"
								type="datetime-local"
								class="date input"
								:disabled="!editing.has(item.key)"
							>

							<select
								v-if="item.value.precision"
								v-model="edits[item.key].precision"
								class="input"
								:disabled="!editing.has(item.key)"
							>
								<option value="minute">Minute</option>
								<option value="hour">Hour</option>
								<option value="day">Day</option>
								<option value="month">Month</option>
								<option value="year">Year</option>
							</select>
						</div>

						<div
							v-if="item.type === 'duration'"
							class="duration"
						>
							<input
								type="number"
								class="input"
								:value="edits[item.key]?.[0] ?? item.value[0]"
								min="0"
								max="100"
								:disabled="!editing.has(item.key)"
								@change="setDuration('h', $event)"
							>H

							<input
								type="number"
								class="input"
								:value="edits[item.key]?.[1] ?? item.value[1]"
								min="0"
								max="59"
								:disabled="!editing.has(item.key)"
								@change="setDuration('m', $event)"
							>M

							<input
								type="number"
								class="input"
								:value="edits[item.key]?.[2] ?? item.value[2]"
								min="0"
								max="59"
								:disabled="!editing.has(item.key)"
								@change="setDuration('s', $event)"
							>S
						</div>
					</div>
				</li>
			</ul>

			<div class="editor-footer">
				<div class="comment">
					<textarea
						v-model="comment"
						rows="3"
						placeholder="Please provide verifiable information supporting your edits."
						class="text input"
					/>
				</div>

				<div class="editor-actions">
					<Checkbox
						v-if="user.role !== 'user'"
						v-tooltip="isApplyDisabled && editing.has('delete') ? { content: 'Delete must be approved by an admin', ariaId: applyTooltipId } : null"
						label="Approve and apply immediately"
						:checked="apply"
						:disabled="isApplyDisabled"
						@change="(checked) => apply = checked"
					/>

					<!-- we don't want the return key to submit the form -->
					<button
						class="button button-primary"
						type="button"
						:disabled="editing.size === 0"
						@click="submit"
					>
						<template v-if="apply">Submit</template>
						<template v-else>Submit for review</template>
					</button>
				</div>
			</div>
		</form>
	</div>
</template>

<style scoped>
.editor {
	flex-grow: 1;
	background: var(--background-dark-10);
}

.editor-header {
	display: flex;
	justify-content: space-between;
	align-items: center;
	padding: 1rem;
}

.heading {
	margin: 0;
}

.row {
	display: flex;
	align-items: center;
	padding: .25rem 1rem;

	.value.disabled {
		color: var(--glass);
	}
}

.key {
	width: 8rem;
	display: inline-flex;
	align-items: center;
	text-transform: capitalize;
	font-weight: bold;
}

.input {
	background: var(--background);
}

.item-header {
	display: flex;
	align-items: center;
}

.value {
	flex-grow: 1;

	.input {
		width: 100%;

		&:disabled {
			color: var(--glass-strong-10);
			background: none;
			border: solid 1px var(--glass-weak-30);
		}
	}

	.duration {
		.input {
			width: 5rem;
			margin-right: .25rem;

			&:not(:first-child) {
				margin-left: .75rem;
			}
		}
	}

	&.disabled {
		pointer-events: none;
	}
}

.date {
	.input {
		width: auto;
	}
}

.item-actions {
	.icon {
		padding: .25rem 1rem;
		fill:  var(--glass);
		overflow: hidden;

		&:hover {
			cursor: pointer;
			fill: var(--text);
		}

		&.active {
			fill: var(--primary);
		}
	}
}

.item-note {
	fill: var(--glass);
	padding: .5rem .75rem;
	cursor: help;

	&:hover {
		fill: var(--primary);
	}
}

.editor-footer {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1rem;
	padding: 1rem 1rem 0 1rem;
	border-top: solid 1px var(--primary-light-30);
	margin: 1rem 0;
}

.comment {
	width: 100%;
	flex-shrink: 0;

	.input {
		width: 100%;
		resize: vertical;
	}
}

.checkbox.delete {
	display: inline-flex;
	gap: 1rem;
	align-items: center;
	font-weight: bold;
}

.value.disabled .delete {
	:deep(.check-checkbox) + .check {
		background: var(--glass-weak-30);
	}
}

.value:not(.disabled) .delete {
	:deep(.check-checkbox:checked) + .check {
		background: var(--error);
	}
}

.editor-actions {
	display: flex;
	flex-direction: column;
	align-items: center;
	gap: 1.5rem;
	margin: .5rem 0;

	.button {
		padding: .5rem 1rem;
		font-size: 1.1rem;
	}
}

.submitted {
	display: flex;
	flex-direction: column;
	align-items: center;
	padding: 1rem;
	font-weight: bold;
	line-height: 1.5;
}

.delete-title {
	display: block;
	margin-top: .5rem;
	max-width: 25rem;
}

.dialog-body {
	padding: 1rem;
}

.dialog-section {
	margin-bottom: 1rem;
	text-align: center;
}

.dialog-actions {
	display: flex;
	justify-content: space-between;
	align-items: center;
}

@media(--small) {
	.row {
		flex-direction: column;
		align-items: stretch;
		margin-bottom: .25rem;
	}

	.item-header {
		margin-bottom: .25rem;
	}

	.key {
		flex-grow: 1;
	}
}
</style>
