<template>
	<div v-if="visible" class="avatar-crop-dialog" @click.self="handleCancel">
		<div class="avatar-crop-dialog__panel">
			<button type="button" class="avatar-crop-dialog__close" @click="handleCancel">
				<SvgIcon name="close" size="24" />
			</button>

			<div class="avatar-crop-dialog__title">{{ t('Settings.avatarCrop.title') }}</div>

			<div class="avatar-crop-dialog__body">
				<div class="cropper-shell">
					<VueCropper
						ref="cropperRef"
						:img="imageUrl"
						:wrapper="{ width: 420, height: 420 }"
						:crop-layout="{ width: 260, height: 260 }"
						:center-box="true"
						:output-type="outputType"
						:output-size="0.92"
						mode="cover"
						crop-color="#ffffff"
						@real-time="handlePreview"
					/>
				</div>

				<div class="preview-column">
					<div class="avatar-preview">
						<img
							v-if="previewUrl"
							:src="previewUrl"
							:style="previewImageStyle"
							alt="avatar preview"
						/>
					</div>

					<div class="cropper-tools">
						<button type="button" class="tool-btn" @click="cropperRef?.zoomOut?.()">
							-
						</button>
						<button type="button" class="tool-btn" @click="cropperRef?.zoomIn?.()">
							+
						</button>
						
					</div>
				</div>
			</div>

			<div class="avatar-crop-dialog__actions">
				<button type="button" class="secondary-btn" :disabled="submitting" @click="handleCancel">
					{{ t('Settings.buttons.cancel') }}
				</button>
				<button type="button" class="primary-btn" :disabled="submitting" @click="handleConfirm">
					{{ submitting ? t('Settings.avatarCrop.processing') : t('Settings.avatarCrop.confirm') }}
				</button>
			</div>
		</div>
	</div>
</template>

<script setup lang="ts">
	import { computed, shallowRef } from 'vue'
	import { useI18n } from 'vue-i18n'
	import { ElMessage } from 'element-plus'
	import { VueCropper } from 'cropper-next-vue'
	import 'cropper-next-vue/style.css'

	type CropperInstance = InstanceType<typeof VueCropper> & {
		getCropBlob?: () => Promise<Blob>
		zoomIn?: (step?: number) => void
		zoomOut?: (step?: number) => void
		rotateLeft?: () => void
		rotateRight?: () => void
	}

	interface PreviewPayload {
		url: string
		img: Record<string, string>
	}

	const props = defineProps<{
		visible: boolean
		imageUrl: string
		fileName: string
		fileType: string
	}>()

	const emit = defineEmits<{
		(event: 'cancel'): void
		(event: 'confirm', file: File): void
	}>()

	const { t } = useI18n()

	const cropperRef = shallowRef<CropperInstance | null>(null)
	const submitting = shallowRef(false)
	const previewUrl = shallowRef('')
	const previewImageStyle = shallowRef<Record<string, string>>({})

	const outputType = computed(() => {
		const subtype = props.fileType.split('/')[1]
		return subtype === 'jpeg' || subtype === 'jpg' || subtype === 'webp' ? subtype : 'png'
	})

	const cropFileType = computed(() =>
		outputType.value === 'jpg' ? 'image/jpeg' : `image/${outputType.value}`
	)

	const cropFileName = computed(() => {
		const baseName = props.fileName.replace(/\.[^.]+$/, '') || 'avatar'
		const extension = outputType.value === 'jpeg' ? 'jpg' : outputType.value
		return `${baseName}-cropped.${extension}`
	})

	const handlePreview = (payload: PreviewPayload) => {
		previewUrl.value = payload.url
		previewImageStyle.value = payload.img
	}

	const handleCancel = () => {
		if (submitting.value) return
		emit('cancel')
	}

	const handleConfirm = async () => {
		if (!cropperRef.value?.getCropBlob) return

		submitting.value = true
		try {
			const blob = await cropperRef.value.getCropBlob()
			const file = new File([blob], cropFileName.value, {
				type: cropFileType.value,
				lastModified: Date.now()
			})
			emit('confirm', file)
		} catch (error) {
			console.warn(error)
			ElMessage.error(t('Settings.messages.avatarCropFailed'))
		} finally {
			submitting.value = false
		}
	}
</script>

<style lang="less" scoped>
	.avatar-crop-dialog {
		position: fixed;
		inset: 0;
		z-index: 2000;
		display: flex;
		align-items: center;
		justify-content: center;
		padding: 2rem;
		background: rgba(0, 0, 0, 0.4);
	}

	.avatar-crop-dialog__panel {
		position: relative;
		width: 78rem;
		padding: 4rem 4.8rem 3.6rem;
		background: #efefef;
		box-shadow: 0 2rem 6rem rgba(35, 35, 35, 0.14);
	}

	.avatar-crop-dialog__close {
		position: absolute;
		top: 2rem;
		right: 2rem;
		display: inline-flex;
		align-items: center;
		justify-content: center;
		border: none;
		padding: 0;
		background: transparent;
		color: #585858;
		cursor: pointer;
	}

	.avatar-crop-dialog__title {
		font-family: 'KaiseiOpti-Bold';
		font-size: 3rem;
		line-height: 3.6rem;
		text-align: center;
		color: #232323;
	}

	.avatar-crop-dialog__body {
		display: flex;
		align-items: center;
		column-gap: 3.2rem;
		margin-top: 3.2rem;
	}

	.cropper-shell {
		width: 42rem;
		height: 42rem;
		overflow: hidden;
		background: #ffffff;
	}

	.preview-column {
		display: flex;
		flex-direction: column;
		align-items: center;
		row-gap: 2.4rem;
		flex: 1;
	}

	.avatar-preview {
		width: 260px;
		height: 260px;
		overflow: hidden;
		border: 0.1rem solid #d8d0c7;
		border-radius: 50%;
		background: #ffffff;

		img {
			max-width: none;
		}
	}

	.cropper-tools {
		display: flex;
		flex-wrap: wrap;
		justify-content: center;
		gap: 1rem;
	}

	.tool-btn,
	.primary-btn,
	.secondary-btn {
		height: 4rem;
		border: 0.1rem solid #c4c4c4;
		background: #ffffff;
		font-family: 'KaiseiOpti-Bold';
		font-size: 1.4rem;
		line-height: 2.4rem;
		color: #232323;
		cursor: pointer;

		&:disabled {
			opacity: 0.6;
			cursor: not-allowed;
		}
	}

	.tool-btn {
		min-width: 5.2rem;
		padding: 0 1.2rem;
	}

	.avatar-crop-dialog__actions {
		display: flex;
		justify-content: center;
		column-gap: 1.2rem;
		margin-top: 3.2rem;
	}

	.primary-btn {
		width: 18rem;
		border-color: #232323;
		background: #232323;
		color: #ffffff;
	}

	.secondary-btn {
		width: 12rem;
	}
</style>
