import { computed, ref, shallowRef, watch, type Ref } from 'vue'
import { ElMessage } from 'element-plus'
import md5 from 'md5'
import {
	fetchUserProfile,
	type UserProfile,
	updateUserProfile,
	verifyEmailCode,
	fetchVerifyCode
} from '@/api/user'
import regionList from '@/utils/area'
import {
	languageValues,
	roleValues,
	type LanguageValue,
	type RoleValue,
	type SecurityDraft,
	type SettingsData
} from './types'
import { validateCase, validateLength, validateSpecial } from '@/views/login/tools'

type Translate = (key: string, ...args: unknown[]) => string

interface UseSettingsFormOptions {
	t: Translate
	locale: Ref<string>
}

// 前端 UI 使用的语言值（用于下拉选择）
const languageLocaleMap: Record<LanguageValue, 'ENGLISH' | 'CHINESE_SIMPLIFIED'> = {
	english: 'ENGLISH',
	chinese: 'CHINESE_SIMPLIFIED'
}

// 后端 API 使用的语言值
const backendLanguageMap: Record<'ENGLISH' | 'CHINESE_SIMPLIFIED', 'en' | 'zh-CN'> = {
	ENGLISH: 'en',
	CHINESE_SIMPLIFIED: 'zh-CN'
}

// 后端语言值转换为前端语言值
const backendToFrontendLanguage: Record<'en' | 'zh-CN', LanguageValue> = {
	en: 'english',
	'zh-CN': 'chinese'
}

const emailPattern = /^[^\s@]+@[^\s@]+\.[^\s@]+$/

const createDefaultData = (): SettingsData => ({
	firstName: '',
	lastName: '',
	email: '',
	username: '',
	roles: [] as RoleValue[],
	language: '',
	region: ''
})

const cloneSettingsData = (data: SettingsData): SettingsData => ({
	firstName: data.firstName,
	lastName: data.lastName,
	email: data.email,
	username: data.username,
	roles: [...data.roles],
	language: data.language,
	region: data.region
})

const normalizeLanguage = (language: string | null | undefined): LanguageValue => {
	if (!language) {
		return '' as LanguageValue
	}

	// 后端返回 'en' 或 'zh-CN'
	const trimmed = language.trim()
	if (trimmed === 'en') {
		return 'english'
	} else if (trimmed === 'zh-CN') {
		return 'chinese'
	}

	return '' as LanguageValue
}

const buildSettingsDataFromProfile = (profile: Partial<UserProfile>): SettingsData => ({
	firstName: profile.firstName || '',
	lastName: profile.lastName || '',
	username: profile.username || '',
	email: profile.email || '',
	roles: profile.roles || [],
	language: normalizeLanguage(profile.language),
	region: profile.region
})

const createEmptySecurityDraft = (): SecurityDraft => ({
	newEmail: '',
	newPassword: '',
	currentPassword: ''
})

export function useSettingsForm({ t, locale }: UseSettingsFormOptions) {
	const sourceData = ref<SettingsData>(createDefaultData())
	const draftData = ref<SettingsData>(cloneSettingsData(sourceData.value))
	const securityDraft = ref<SecurityDraft>(createEmptySecurityDraft())
	const isEditing = shallowRef(false)
	const saving = shallowRef(false)
	const isVerificationDialogVisible = shallowRef(false)
	const verificationTargetEmail = shallowRef('')
	const verifiedEmail = shallowRef('')
	const verificationCode = shallowRef('')
	const isEditingEmail = shallowRef(false)
	const isEditingPassword = shallowRef(false)

	const roleList = computed(() =>
		roleValues.map((value) => ({
			name: t(`Settings.roles.${value}`),
			value
		}))
	)

	const languageList = computed(() =>
		languageValues.map((value) => ({
			label: t(`Settings.languages.${value}`),
			value
		}))
	)

	const displayData = computed(() => (isEditing.value ? draftData.value : sourceData.value))
	const normalizedNewEmail = computed(() => securityDraft.value.newEmail.trim())
	const hasNewEmailChange = computed(
		() =>
			normalizedNewEmail.value.length > 0 &&
			normalizedNewEmail.value !== sourceData.value.email
	)
	const isEmailVerified = computed(
		() => hasNewEmailChange.value && verifiedEmail.value === normalizedNewEmail.value
	)
	const hasNewPasswordChange = computed(() => securityDraft.value.newPassword.length > 0)
	const needsEmailVerification = computed(
		() => (hasNewEmailChange.value || hasNewPasswordChange.value) && !isEmailVerified.value
	)
	const displayLanguageLabel = computed(() =>
		displayData.value.language ? t(`Settings.languages.${displayData.value.language}`) : ''
	)
	const displayRegionLabel = computed(() => {
		if (displayData.value.region) {
			const regionItem = regionList.find((item) => item.value === displayData.value.region)
			return regionItem.key
		} else {
			return ''
		}
	})

	const fullName = computed(() => {
		const data = displayData.value
		return `${data.firstName} ${data.lastName}`.trim()
	})

	const roleModel = computed<RoleValue[]>({
		get: () => displayData.value.roles,
		set: (value) => {
			if (isEditing.value) {
				draftData.value.roles = value
				return
			}

			sourceData.value.roles = value
		}
	})

	const resetEmailVerificationState = () => {
		isVerificationDialogVisible.value = false
		verificationTargetEmail.value = ''
		verifiedEmail.value = ''
		verificationCode.value = ''
	}

	const syncAppLanguage = (language: LanguageValue) => {
		const nextLocale = languageLocaleMap[language]
		locale.value = nextLocale
		localStorage.setItem('language', nextLocale)
	}

	const loadUserProfile = async () => {
		try {
			const profile = (await fetchUserProfile()) as Partial<UserProfile>
			const nextData = buildSettingsDataFromProfile(profile)
			sourceData.value = cloneSettingsData(nextData)
			draftData.value = cloneSettingsData(sourceData.value)

			if (sourceData.value.language) {
				syncAppLanguage(sourceData.value.language as LanguageValue)
			}
		} catch (error) {
			console.warn(error)
		}
	}

	const resetDraftState = () => {
		draftData.value = cloneSettingsData(sourceData.value)
		securityDraft.value = createEmptySecurityDraft()
		resetEmailVerificationState()
		isEditingEmail.value = false
		isEditingPassword.value = false
	}

	const handleEdit = () => {
		resetDraftState()
		isEditing.value = true
	}

	const resetSecurityEmail = () => {
		securityDraft.value.newEmail = ''
		resetEmailVerificationState()
		isEditingEmail.value = false
	}

	const resetSecurityPassword = () => {
		securityDraft.value.newPassword = ''
		securityDraft.value.currentPassword = ''
		isEditingPassword.value = false
	}

	const handleEditEmail = () => {
		isEditingEmail.value = true
	}

	const handleEditPassword = () => {
		isEditingPassword.value = true
	}

	const handleDiscard = () => {
		resetDraftState()
		isEditing.value = false
	}

	const closeVerificationDialog = () => {
		isVerificationDialogVisible.value = false
		verificationTargetEmail.value = ''
	}

	const handleVerifyEmail = () => {
		if (!hasNewEmailChange.value && !hasNewPasswordChange.value) return

		const nextEmail = normalizedNewEmail.value
		const newPassword = securityDraft.value.newPassword
		const currentPassword = securityDraft.value.currentPassword
		let targetEmail = ''

		if (hasNewPasswordChange.value) {
			if (validateLength(newPassword)) {
				ElMessage.warning(t('Settings.messages.passwordLengthError', { min: 6, max: 20 }))
				return
			}

			if (validateSpecial(newPassword)) {
				ElMessage.warning(t('Settings.messages.passwordSpecial'))
				return
			}

			if (validateCase(newPassword)) {
				ElMessage.warning(t('Settings.messages.passwordCase'))
				return
			}

			if (newPassword === currentPassword) {
				ElMessage.warning(t('Settings.messages.passwordNotSameAsOld'))
				return
			}
		}

		if (hasNewEmailChange.value) {
			if (!emailPattern.test(nextEmail)) {
				ElMessage.warning(t('Settings.messages.invalidEmail'))
				return
			}

			if (nextEmail === sourceData.value.email) {
				ElMessage.warning(t('Settings.messages.sameEmail'))
				return
			}

			if (verifiedEmail.value === nextEmail) {
				ElMessage.success(t('Settings.messages.alreadyVerified'))
				return
			}

			targetEmail = nextEmail
		} else if (hasNewPasswordChange.value) {
			targetEmail = sourceData.value.email
		}

		if (!targetEmail) return

		verificationTargetEmail.value = targetEmail
		handleSendVerifyCode()
	}

	const handleSendVerifyCode = () => {
		fetchVerifyCode().then(() => {
			ElMessage.success(t('Settings.messages.verificationCodeSent'))
			isVerificationDialogVisible.value = true
		})
	}

	const handleVerificationSubmit = (code: string) => {
		if (code.length !== 6) {
			ElMessage.warning(t('Settings.messages.enterVerificationCode'))
			return
		}
		// send code to backend and store the code locally so save() can include it
		verifyEmailCode(code).then((res) => {
			verificationCode.value = code
			verifiedEmail.value = verificationTargetEmail.value
			closeVerificationDialog()
			ElMessage.success(t('Settings.messages.verificationCompleted'))
		})
	}

	const handleSave = async () => {
		if (hasNewEmailChange.value && !isEmailVerified.value) {
			ElMessage.warning(t('Settings.messages.verifyEmailBeforeSave'))
			return
		}

		if (hasNewPasswordChange.value && !verificationCode.value) {
			ElMessage.warning(t('Settings.messages.verifyEmailBeforeSave'))
			return
		}

		// 将前端语言值转换为后端格式
		let backendLanguage = ''
		if (draftData.value.language) {
			const i18nLocale = languageLocaleMap[draftData.value.language as LanguageValue]
			backendLanguage = backendLanguageMap[i18nLocale]
		}

		const nextData: UserProfile = {
			firstName: draftData.value.firstName.trim(),
			lastName: draftData.value.lastName.trim(),
			username: draftData.value.username.trim(),
			email: securityDraft.value.newEmail.trim(),
			roles: draftData.value.roles as string[],
			language: backendLanguage,
			region: draftData.value.region,
			newPassword: '',
			oldPassword: '',
			verifyCode: ''
		}

		// 如果改邮箱或改密码，需要添加验证码和密码信息
		if (hasNewEmailChange.value || hasNewPasswordChange.value) {
			nextData.verifyCode = verificationCode.value
		}

		if (hasNewPasswordChange.value) {
			nextData.oldPassword = md5(securityDraft.value.currentPassword)
			nextData.newPassword = md5(securityDraft.value.newPassword)
		}

		const previousLanguage = sourceData.value.language
		saving.value = true

		try {
			await updateUserProfile(nextData)

			// 将后端返回的语言值转换为前端格式
			const frontendLanguage = backendLanguage
				? backendToFrontendLanguage[backendLanguage as 'en' | 'zh-CN']
				: ''

			const settingsData: SettingsData = {
				firstName: nextData.firstName,
				lastName: nextData.lastName,
				username: nextData.username,
				email: nextData.email || draftData.value.email,
				roles: nextData.roles as RoleValue[],
				language: frontendLanguage,
				region: nextData.region as any
			}
			sourceData.value = cloneSettingsData(settingsData)
			console.log(nextData)

			if (frontendLanguage && frontendLanguage !== previousLanguage) {
				syncAppLanguage(frontendLanguage as LanguageValue)
			}

			draftData.value = cloneSettingsData(sourceData.value)
			securityDraft.value = createEmptySecurityDraft()
			resetEmailVerificationState()
			isEditing.value = false
			isEditingEmail.value = false
			isEditingPassword.value = false
			ElMessage.success(t('Settings.messages.settingsUpdated'))
		} catch (error) {
			console.warn(error)
		} finally {
			saving.value = false
		}
	}

	watch(
		() => securityDraft.value.newEmail,
		(value) => {
			const trimmedValue = value.trim()

			if (verifiedEmail.value && trimmedValue !== verifiedEmail.value) {
				verifiedEmail.value = ''
			}

			if (
				isVerificationDialogVisible.value &&
				verificationTargetEmail.value &&
				trimmedValue !== verificationTargetEmail.value
			) {
				closeVerificationDialog()
			}
		}
	)

	return {
		sourceData,
		draftData,
		securityDraft,
		isEditing,
		saving,
		isVerificationDialogVisible,
		verificationTargetEmail,
		roleList,
		languageList,
		regionList,
		displayData,
		isEmailVerified,
		displayLanguageLabel,
		displayRegionLabel,
		fullName,
		roleModel,
		needsEmailVerification,
		isEditingEmail,
		isEditingPassword,
		handleEdit,
		handleDiscard,
		handleSave,
		resetSecurityEmail,
		resetSecurityPassword,
		handleEditEmail,
		handleEditPassword,
		handleVerifyEmail,
		handleSendVerifyCode,
		handleVerificationSubmit,
		closeVerificationDialog,
		loadUserProfile
	}
}
