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

import Merge from '#/components/actors/merge.vue';
import EditAugmentation from '#/components/edit/augmentation.vue';
import Avatar from '#/components/edit/avatar.vue';
import EditFigure from '#/components/edit/figure.vue';
import EditPenis from '#/components/edit/penis.vue';
import EditPlace from '#/components/edit/place.vue';
import EditSocials from '#/components/edit/socials.vue';
import Checkbox from '#/components/form/checkbox.vue';
import Ellipsis from '#/components/loading/ellipsis.vue';

import {
	// get,
	post,
} from '#/src/api.js';

import verifyAbility from '#/utils/verify-ability.js';

const pageContext = inject('pageContext');

const user = pageContext.user;
const actor = ref(pageContext.pageProps.actor || null);

const fields = computed(() => [
	...(actor.value?.photos.length > 0
		? [{
				key: 'avatar',
				type: 'avatar',
				value: actor.value.avatar?.id,
				options: actor.value.photos,
			}]
		: []),
	...(user.role === 'admin'
		? [{
				key: 'name',
				type: 'string',
				value: actor.value?.name,
			}]
		: []),
	{
		key: 'gender',
		type: 'select',
		value: actor.value?.gender || null,
		options: [null, 'female', 'male', 'transsexual', 'other'],
		inline: true,
	},
	{
		key: 'dateOfBirth',
		label: 'date of birth',
		type: 'date',
		value: actor.value?.dateOfBirth
			? format(actor.value.dateOfBirth, 'yyyy-MM-dd')
			: null,
		inline: true,
	},
	{
		key: 'socials',
		type: 'socials',
		value: actor.value?.socials || [],
	},
	{
		key: 'origin',
		type: 'place',
		value: {
			country: actor.value?.origin?.country?.alpha2 || null,
			place: [actor.value?.origin?.city, actor.value?.origin?.state].filter(Boolean).join(', '),
		},
	},
	{
		key: 'residence',
		type: 'place',
		value: {
			country: actor.value?.residence?.country?.alpha2 || null,
			place: [actor.value?.residence?.city, actor.value?.residence?.state].filter(Boolean).join(', '),
		},
	},
	{
		key: 'ethnicity',
		type: 'string',
		value: actor.value?.ethnicity || null,
		suggestions: [
			'Asian',
			'Black',
			'Indian',
			'Latina',
			'White',
		],
	},
	{
		key: 'size',
		type: 'size',
		value: {
			metricHeight: actor.value?.height?.metric || null,
			metricWeight: actor.value?.weight?.metric || null,
			imperialHeight: actor.value?.height?.imperial || [],
			imperialWeight: actor.value?.weight?.imperial || null,
		},
	},
	{
		key: 'figure',
		type: 'figure',
		value: {
			bust: actor.value?.bust || null,
			cup: actor.value?.cup || null,
			waist: actor.value?.waist || null,
			hip: actor.value?.hip || null,
		},
	},
	{
		key: 'augmentation',
		type: 'augmentation',
		note: 'Provide explicit evidence, such as social media posts, visible scarring, or before/after. Avoid "it\'s obvious".',
		value: {
			naturalBoobs: actor.value?.naturalBoobs ?? null,
			boobsVolume: actor.value?.boobsVolume || null,
			boobsImplant: actor.value?.boobsImplant || null,
			boobsPlacement: actor.value?.boobsPlacement || null,
			boobsIncision: actor.value?.boobsIncision || null,
			boobsSurgeon: actor.value?.boobsSurgeon || null,
			naturalButt: actor.value?.naturalButt ?? null,
			buttVolume: actor.value?.buttVolume || null,
			buttImplant: actor.value?.buttImplant || null,
			naturalLips: actor.value?.naturalLips ?? null,
			lipsVolume: actor.value?.lipsVolume || null,
			naturalLabia: actor.value?.naturalLabia ?? null,
		},
	},
	{
		key: 'hairColor',
		label: 'hair color',
		type: 'select',
		value: actor.value?.hairColor || null,
		options: [
			null,
			'black',
			'blonde',
			'brown',
			'red',
			'gray',
			'blue',
			'green',
			'pink',
			'purple',
		],
		inline: true,
	},
	{
		key: 'eyes',
		label: 'eye color',
		type: 'select',
		value: actor.value?.eyes || null,
		options: [
			null,
			'blue',
			'brown',
			'gray',
			'green',
			'hazel',
		],
		inline: true,
	},
	{
		key: 'tattoos',
		type: 'has',
		value: {
			has: actor.value?.hasTattoos ?? null,
			description: actor.value?.tattoos || null,
		},
	},
	{
		key: 'piercings',
		type: 'has',
		note: 'Excludes earrings',
		value: {
			has: actor.value?.hasPiercings ?? null,
			description: actor.value?.piercings || null,
		},
	},
	{
		key: 'agency',
		type: 'string',
		value: actor.value?.agency || null,
		suggestions: [
			'101 Modeling',
			'Adult Talent Managers (ATMLA)',
			'AMA Modeling',
			'The Bakery Talent',
			'Coxxx Models',
			'East Coast Talent (ECT)',
			'Hussie Models',
			'Invision Models',
			'OC Modeling',
			'Spiegler Girls',
		],
	},
	{
		key: 'penis',
		type: 'penis',
		value: {
			metricLength: actor.value?.penisLength?.metric || null,
			metricGirth: actor.value?.penisGirth?.metric || null,
			imperialLength: actor.value?.penisLength?.imperial || null,
			imperialGirth: actor.value?.penisGirth?.imperial || null,
			isCircumcised: actor.value?.isCircumcised || null,
		},
	},
	{
		key: 'dateOfDeath',
		label: 'date of death',
		type: 'date',
		value: actor.value?.dateOfDeath
			? format(actor.value.dateOfDeath, 'yyyy-MM-dd')
			: null,
	},
	{
		key: 'allowGlobalMatch',
		label: 'global match',
		type: 'has',
		note: 'Allow this actor to be assigned to scenes automatically, overriding single-name protections.',
		hasDescription: false,
		value: {
			has: actor.value?.allowGlobalMatch ?? null,
		},
	},
]
	.filter((field) => (actor.value ? true : ['name', 'gender'].includes(field.key)))
	.map((field) => ({
		...field,
		forced: actor.value ? field.forced : true,
	})));

const editing = ref(new Set(actor.value ? [] : ['name', 'gender']));
const edits = ref(Object.fromEntries(fields.value.map((field) => [field.key, field.value])));
const creating = !actor.value;
const comment = ref(null);
const apply = ref(user.role !== 'user');
const submitting = ref(false);
const submitted = ref(false);
const showMergeDialog = ref(false);

const sizeUnits = ref('metric');
const figureUnits = ref('us');
const penisUnits = ref('imperial');

function toggleField(item) {
	if (editing.value.has(item.key)) {
		editing.value.delete(item.key);
		// delete edits.value[item.key];

		return;
	}

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

function setAvatar(avatarId) {
	edits.value.avatar = avatarId;
}

const keyMap = {
	origin: {
		country: 'originCountry',
		place: 'originPlace',
	},
	residence: {
		country: 'residenceCountry',
		place: 'residencePlace',
	},
	tattoos: {
		has: 'hasTattoos',
		description: 'tattoos',
	},
	piercings: {
		has: 'hasPiercings',
		description: 'piercings',
	},
	allowGlobalMatch: {
		has: 'allowGlobalMatch',
	},
};

const groupMap = {
	penisLength: 'penis',
	penisGirth: 'penis',
	height: 'size',
	weight: 'size',
};

async function submit() {
	try {
		submitting.value = true;

		await post('/revisions/actors', {
			actorId: actor.value.id,
			edits: omit({
				...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]]];
				})),
				...Object.fromEntries(Object.entries({
					height: sizeUnits.value === 'imperial' ? edits.value.size.imperialHeight : edits.value.size.metricHeight,
					weight: sizeUnits.value === 'imperial' ? edits.value.size.imperialWeight : edits.value.size.metricWeight,
					penisLength: penisUnits.value === 'imperial' ? edits.value.penis.imperialLength : edits.value.penis.metricLength,
					penisGirth: penisUnits.value === 'imperial' ? edits.value.penis.imperialGirth : edits.value.penis.metricGirth,
				}).filter(([key]) => editing.value.has(groupMap[key] || key))),
			}, [
				'metricHeight',
				'metricWeight',
				'imperialHeight',
				'imperialWeight',
				'metricLength',
				'metricGirth',
				'imperialLength',
				'imperialGirth',
			]),
			sizeUnits: sizeUnits.value,
			figureUnits: figureUnits.value,
			penisUnits: penisUnits.value,
			comment: comment.value,
			apply: apply.value,
		}, {
			successFeedback: 'Your revision has been submitted for approval.',
			appendErrorMessage: true,
		});

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

		submitted.value = true;

		// actor.value = await get(`/actors/${actor.value.id}`);
	}
	catch (error) {
		console.error(error);
	}
}
</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 v-if="actor">
				<li>
					<a
						:href="`/actor/${actor.id}/${actor.slug}`"
						class="link"
					>{{ creating ? 'Go' : 'Return' }} to actor</a>
				</li>

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

				<li v-if="!creating">
					<a
						:href="`/actor/revs/${actor.id}/${actor.slug}`"
						class="link"
					>Go to actor revisions</a>
				</li>

				<li v-if="!creating">
					<a
						:href="`/user/${user.username}/revisions/actors`"
						class="link"
					>Go to user revisions</a>
				</li>

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

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

				<span class="header-actions">
					<span
						v-if="verifyAbility(user, 'actor', 'merge')"
						target="_blank"
						class="link noshrink"
						@click="showMergeDialog = true"
					>Merge</span>

					<Merge
						v-if="showMergeDialog"
						:actors="[actor]"
						@close="showMergeDialog = false"
					/>

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

			<div
				v-else
				class="editor-header"
			>
				<h2 class="heading ellipsis">Add actor</h2>
			</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"
							/>
						</div>

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

					<div
						class="value"
						:class="{ disabled: !editing.has(item.key) }"
					>
						<input
							v-if="item.type === 'string'"
							v-model="edits[item.key]"
							class="string input"
							:list="item.suggestions && `suggestions-${item.key}`"
							:disabled="!editing.has(item.key)"
						>

						<datalist
							v-if="item.suggestions"
							:id="`suggestions-${item.key}`"
						>
							<option
								v-for="(suggestion, index) in item.suggestions"
								:key="`suggestion-${item.key}-${index}`"
							>{{ suggestion }}</option>
						</datalist>

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

						<template v-if="item.type === 'number'">
							<input
								v-model="edits[item.key]"
								type="number"
								:max="item.max"
								:min="item.min"
								class="number input"
								:disabled="!editing.has(item.key)"
							>{{ item.unit }}
						</template>

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

						<select
							v-if="item.type === 'select'"
							v-model="edits[item.key]"
							class="select input"
							:disabled="!editing.has(item.key)"
						>
							<option
								v-for="option in item.options"
								:key="`${item.key}-option-${option}`"
								:value="typeof option?.value === 'undefined' ? option : option.value"
							>{{ option?.label || option }}</option>
						</select>

						<div
							v-if="item.type === 'size'"
							class="figure size"
						>
							<div class="value-section">
								<span class="value-label">Units</span>

								<select
									v-model="sizeUnits"
									class="input"
									:disabled="!editing.has(item.key)"
								>
									<option value="metric">Metric</option>
									<option value="imperial">Imperial</option>
								</select>
							</div>

							<span class="figure-height">
								<div class="value-section">
									<span class="value-label">Height</span>

									<span v-if="sizeUnits === 'metric'">
										<input
											v-model="edits[item.key].metricHeight"
											type="number"
											class="input"
											:disabled="!editing.has(item.key)"
										> cm
									</span>

									<span v-if="sizeUnits === 'imperial'">
										<input
											v-model="edits[item.key].imperialHeight[0]"
											type="number"
											class="input"
											:disabled="!editing.has(item.key)"
										> ft

										<input
											v-model="edits[item.key].imperialHeight[1]"
											type="number"
											class="input"
											:disabled="!editing.has(item.key)"
										> in
									</span>
								</div>
							</span>

							<span class="figure-weight">
								<div class="value-section">
									<span class="value-label">Weight</span>

									<span v-if="sizeUnits === 'metric'">
										<input
											v-model="edits[item.key].metricWeight"
											type="number"
											class="input"
											:disabled="!editing.has(item.key)"
										> kg
									</span>

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

										<template v-if="sizeUnits === 'imperial'">&nbsp;lbs</template>
										<template v-else>&nbsp;kg</template>
									</span>
								</div>
							</span>
						</div>

						<EditSocials
							v-if="item.type === 'socials'"
							:edits="edits"
							:editing="editing"
							@socials="(socials) => edits.socials = socials"
						/>

						<EditPlace
							v-if="item.type === 'place'"
							:item="item"
							:edits="edits"
							:editing="editing"
							@place="(place) => edits[item.key] = place"
						/>

						<EditFigure
							v-if="item.type === 'figure'"
							:edits="edits"
							:editing="editing"
							:units="figureUnits"
							@figure="(figure) => edits.figure = figure"
							@units="(units) => figureUnits = units"
						/>

						<EditAugmentation
							v-if="item.type === 'augmentation'"
							:edits="edits"
							:editing="editing"
							@augmentation="(augmentation) => edits.augmentation = augmentation"
						/>

						<EditPenis
							v-if="item.type === 'penis'"
							:edits="edits"
							:editing="editing"
							:units="penisUnits"
							@penis="(penis) => edits.penis = penis"
							@units="(units) => penisUnits = units"
						/>

						<div
							v-if="item.type === 'has'"
							class="has"
						>
							<select
								v-model="edits[item.key].has"
								class="select input"
								:disabled="!editing.has(item.key)"
							>
								<option :value="null" />
								<option :value="true">Yes</option>
								<option :value="false">No</option>
							</select>

							<input
								v-if="item.hasDescription !== false"
								v-model="edits[item.key].description"
								class="description input"
								placeholder="Description"
								:disabled="!editing.has(item.key)"
							>
						</div>

						<div
							v-if="item.type === 'avatar'"
							class="avatars"
							:class="{ disabled: !editing.has(item.key) }"
						>
							<Avatar
								v-for="avatar in item.options"
								:key="`avatar-${avatar.id}`"
								:avatar="avatar"
								:class="{ selected: edits[item.key] === avatar.id }"
								@click="setAvatar(avatar.id)"
							/>
						</div>
					</div>
				</li>
			</ul>

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

				<div class="editor-actions">
					<Checkbox
						v-if="user.role !== 'user' && actor"
						label="Approve and apply immediately"
						:checked="apply"
						:disabled="editing.size === 0"
						@change="(checked) => apply = checked"
					/>

					<Ellipsis v-if="submitting" />

					<!-- we don't want the return key to submit the form -->
					<button
						v-else
						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>
.editor {
	flex-grow: 1;
	background: var(--background-dark-10);

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

	.header-actions {
		display: flex;
		flex-direction: row;
		gap: 1rem;
		align-items: center;

		.link {
			cursor: pointer;
		}
	}

	.heading {
		margin: 0;
	}

	.row {
		display: flex;
		align-items: center;
		padding: .25rem 1rem;
		margin-bottom: .25rem;
		overflow: hidden;

		&.inline {
			display: inline-flex;

			& + .inline .key {
				width: auto;
			}
		}
	}

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

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

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

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

	.row .input {
		height: 2.5rem;
		flex-shrink: 0;
		min-width: 7rem;
	}

	.select {
		text-transform: capitalize;
	}

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

	.value {
		display: flex;
		align-items: center;
		flex-grow: 1;
		overflow: hidden;

		.input {
			flex-grow: 1;

			&: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;
				}
			}
		}

		.number.input {
			width: 6rem;
			flex-grow: 0;
			margin-right: .5rem;
		}

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

	.value-section {
		max-width: 100%;
		display: flex;
		flex-direction: column;
	}

	.value-label {
		padding: 0 .25rem;
		margin-bottom: .25rem;
		color: var(--glass-strong-10);
		font-size: .8rem;
		font-weight: bold;
	}

	.value-divide {
		padding-right: 1rem;
		border-right: solid 1px var(--glass-weak-30);
		margin-right: .5rem;
	}

	.place,
	.has,
	.figure {
		display: flex;
		align-items: center;
		flex-wrap: wrap;
		gap: .5rem;
		overflow: hidden;
	}

	.figure {
		.input[type="number"] {
			width: 5rem;
		}

		.input[type="number"].volume {
			width: 6rem;
		}
	}

	.figure-bust {
		display: flex;
		align-items: center;
	}

	.has {
		flex-grow: 1;

		.select {
			flex-grow: 0;
		}

		.description {
			flex-grow: 1;
		}
	}

	.avatars {
		width: 100%;
		display: flex;
		gap: .25rem;
		padding-bottom: .5rem;
		overflow-x: auto;

		&.disabled {
			opacity: .5;
		}
	}

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

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

			&.active {
				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;
		}
	}

	.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;
	}
}

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

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

		.key {
			flex-grow: 1;
		}
	}

	.editor-header {
		flex-direction: column;
	}
}
</style>
