<template>
	<passport-screen :title="copy.title" :subtitle="copy.subtitle" :kicker="copy.kicker" :crumb="copy.crumb">
		<view class="pp-enroll-steps">
			<view
				v-for="(step, idx) in steps"
				:key="step.id"
				class="pp-enroll-steps__node"
				:class="{
					'pp-enroll-steps__node--done': idx < activeIdx,
					'pp-enroll-steps__node--on': idx === activeIdx
				}"
			>
				<view class="pp-enroll-steps__bubble">
					<text class="pp-enroll-steps__num">{{ idx + 1 }}</text>
				</view>
				<text class="pp-enroll-steps__label">{{ step.label }}</text>
				<view v-if="idx < steps.length - 1" class="pp-enroll-steps__bar" />
			</view>
		</view>

		<view class="pp-enroll-field">
			<text class="pp-enroll-field__label">{{ copy.handsetLabel }}</text>
			<view class="pp-enroll-field__row">
				<region-picker v-model="region" :title="copy.regionTitle" :search-placeholder="copy.regionSearch" :empty-text="copy.regionEmpty" />
				<input
					v-model="form.handset"
					class="pp-enroll-input pp-enroll-input--handset"
					:placeholder="copy.handsetPlaceholder"
					placeholder-class="pp-enroll-input__placeholder"
					type="number"
					maxlength="15"
					@input="onHandsetInput"
				/>
			</view>
		</view>

		<view class="pp-enroll-field">
			<text class="pp-enroll-field__label">{{ copy.secretLabel }}</text>
			<view class="pp-enroll-input pp-enroll-input--solo">
				<input
					v-model="form.secret"
					class="pp-enroll-input__field"
					:placeholder="copy.secretPlaceholder"
					placeholder-class="pp-enroll-input__placeholder"
					:password="!secretVisible"
					maxlength="20"
				/>
				<text class="pp-enroll-input__action" @tap="secretVisible = !secretVisible">{{ secretVisible ? copy.hide : copy.show }}</text>
			</view>
			<view class="pp-enroll-meter">
				<view
					v-for="bar in 3"
					:key="bar"
					class="pp-enroll-meter__bar"
					:class="meterClass(bar)"
				/>
				<text class="pp-enroll-meter__hint">{{ secretHint }}</text>
			</view>
		</view>

		<view class="pp-enroll-field">
			<view class="pp-enroll-field__head">
				<text class="pp-enroll-field__label">{{ copy.passcodeLabel }}</text>
				<text
					class="pp-enroll-field__hint"
					:class="{ 'pp-enroll-field__hint--off': !coolReady || sending }"
					@tap="onRequestPasscode"
				>
					{{ coolReady ? (sending ? copy.sending : copy.send) : `${coolLeft}s ${copy.resend}` }}
				</text>
			</view>
			<passcode-grid v-model="form.passcode" :alert="passcodeAlert" />
		</view>

		<button
			class="pp-enroll-submit"
			:class="{ 'pp-enroll-submit--busy': submitting }"
			:disabled="submitting"
			@tap="onSubmit"
		>
			<text class="pp-enroll-submit__text">{{ submitting ? copy.submitting : copy.submit }}</text>
		</button>

		<policy-pledge
			ref="pledge"
			v-model="form.accepted"
			:prefix="copy.pledgePrefix"
			:terms-label="copy.termsLabel"
			:separator="copy.pledgeJoin"
			:privacy-label="copy.privacyLabel"
			:suffix="copy.pledgeSuffix"
		/>

		<template #footer>
			<view class="pp-enroll-foot">
				<text class="pp-enroll-foot__text">{{ copy.footTip }}</text>
				<text class="pp-enroll-foot__cta" @tap="goSignin">{{ copy.footCta }}</text>
			</view>
		</template>
	</passport-screen>
</template>

<script>
import PassportScreen from '@/components/passport-kit/passport-screen.vue'
import RegionPicker from '@/components/passport-kit/region-picker.vue'
import PasscodeGrid from '@/components/passport-kit/passcode-grid.vue'
import PolicyPledge from '@/components/passport-kit/policy-pledge.vue'
import resendCooldown from '@/common/mixins/resend-cooldown'
import { requestPasscode, enrollAccount, sessionByCredential, verifyHandsetUsed } from '@/features/passport/credential-bridge'
import { auditEnrollForm, looksLikeHandset, secretInRange, trimHandset } from '@/features/passport/form-rules'
import { DEFAULT_REGION } from '@/features/passport/region-dialcodes'

export default {
	components: { PassportScreen, RegionPicker, PasscodeGrid, PolicyPledge },
	mixins: [resendCooldown],
	data() {
		return {
			region: DEFAULT_REGION,
			form: { handset: '', secret: '', passcode: '', accepted: true },
			secretVisible: false,
			sending: false,
			submitting: false,
			ticketId: '',
			passcodeAlert: false,
			redirect: ''
		}
	},
	computed: {
		copy() {
			const t = this.$t.bind(this)
			return {
				kicker: t('passport.kicker-join'),
				crumb: t('passport.crumb-signup'),
				title: t('passport.title-enroll'),
				subtitle: t('passport.subtitle-enroll'),
				handsetLabel: t('passport.label-handset'),
				handsetPlaceholder: t('passport.ph-handset'),
				modalTakenTitle: t('passport.modal-taken-title'),
				modalTakenContent: t('passport.modal-taken-content'),
				modalTakenConfirm: t('passport.modal-taken-confirm'),
				modalTakenCancel: t('passport.modal-taken-cancel'),
				secretLabel: t('passport.label-secret-set'),
				secretPlaceholder: t('passport.ph-secret-set'),
				passcodeLabel: t('passport.label-passcode'),
				send: t('passport.btn-send-2'),
				sending: t('passport.btn-sending'),
				resend: t('passport.btn-resend-suffix'),
				show: t('passport.btn-show'),
				hide: t('passport.btn-hide'),
				submit: t('passport.btn-enroll'),
				submitting: t('passport.btn-enroll-busy'),
				footTip: t('passport.foot-have-account'),
				footCta: t('passport.foot-go-signin'),
				regionTitle: t('passport.region-title'),
				regionSearch: t('passport.region-search'),
				regionEmpty: t('passport.region-empty'),
				pledgePrefix: t('passport.pledge-prefix-enroll'),
				pledgeJoin: t('passport.pledge-and'),
				termsLabel: t('passport.pledge-terms'),
				privacyLabel: t('passport.pledge-privacy'),
				pledgeSuffix: t('passport.pledge-suffix-enroll')
			}
		},
		steps() {
			const t = this.$t.bind(this)
			return [
				{ id: 'handset', label: t('passport.step-handset') },
				{ id: 'secret',  label: t('passport.step-secret') },
				{ id: 'verify',  label: t('passport.step-verify') }
			]
		},
		activeIdx() {
			if (!looksLikeHandset(this.form.handset)) return 0
			if (!secretInRange(this.form.secret)) return 1
			return 2
		},
		secretStrength() {
			const v = String(this.form.secret || '')
			if (!v) return 0
			let score = 0
			if (v.length >= 6) score += 1
			if (/[A-Z]/.test(v) && /[a-z]/.test(v)) score += 1
			if (/\d/.test(v) && /[^\dA-Za-z]/.test(v)) score += 1
			if (v.length >= 12) score = Math.max(score, 3)
			return Math.min(3, score)
		},
		secretHint() {
			const t = this.$t.bind(this)
			if (!this.form.secret) return t('passport.meter-hint')
			return [
				t('passport.meter-weak'),
				t('passport.meter-mid'),
				t('passport.meter-good'),
				t('passport.meter-great')
			][this.secretStrength]
		}
	},
	onLoad(query) {
		if (query && query.handset) {
			try {
				this.form.handset = trimHandset(decodeURIComponent(query.handset))
			} catch (_) {
				this.form.handset = trimHandset(query.handset)
			}
		}
		if (query && query.mobile) {
			this.form.handset = trimHandset(query.mobile)
		}
		if (query && query.region) {
			try { 
				this.region = String(decodeURIComponent(query.region)).replace(/^\+/, '')
			} catch (_) {
				this.region = String(query.region).replace(/^\+/, '')
			}
		}
		if (query && query.url) this.redirect = decodeURIComponent(query.url)
		if (query && query.redirect) this.redirect = decodeURIComponent(query.redirect)
	},
	methods: {
		meterClass(bar) {
			if (bar <= this.secretStrength) {
				if (this.secretStrength === 1) return 'pp-enroll-meter__bar--weak'
				if (this.secretStrength === 2) return 'pp-enroll-meter__bar--ok'
				return 'pp-enroll-meter__bar--great'
			}
			return ''
		},
		onHandsetInput(e) {
			this.form.handset = trimHandset(e.detail.value)
		},
		toast(msg) {
			if (this.$appKit && this.$appKit.msg) this.$appKit.msg(msg)
			else uni.showToast({ title: msg, icon: 'none' })
		},
		flashPledge() {
			const node = this.$refs.pledge
			if (node && typeof node.flash === 'function') node.flash()
		},
		promptTakenHandset() {
			uni.showModal({
				title: this.copy.modalTakenTitle,
				content: this.copy.modalTakenContent,
				confirmText: this.copy.modalTakenConfirm,
				cancelText: this.copy.modalTakenCancel,
				success: (res) => {
					if (res.confirm) this.goSignin()
				}
			})
		},
		async onRequestPasscode() {
			if (!this.coolReady || this.sending) return
			if (!looksLikeHandset(this.form.handset)) {
				this.toast(this.$t('passport.err-handset'))
				return
			}
			this.sending = true
			try {
				const { taken } = await verifyHandsetUsed({
					handset: this.form.handset,
					region: this.region
				})
				if (taken) {
					this.promptTakenHandset()
					return
				}
				const { ticketId, needHumanCheck } = await requestPasscode({
					scene: 'register',
					handset: this.form.handset,
					region: this.region
				})
				if (needHumanCheck) {
					this.toast(this.$t('passport.tip-need-captcha'))
				} else {
					this.ticketId = ticketId
					this.coolStart(60)
					this.toast(this.$t('passport.tip-code-sent'))
				}
			} catch (err) {
				this.toast((err && err.message) || this.$t('passport.tip-code-failed'))
			} finally {
				this.sending = false
			}
		},
		goSignin() {
			const params = [`mode=secret`, `handset=${encodeURIComponent(this.form.handset)}`, `region=${encodeURIComponent(this.region)}`]
			if (this.redirect) params.push(`redirect=${encodeURIComponent(this.redirect)}`)
			uni.navigateTo({ url: `/pages/passport/signin?${params.join('&')}` })
		},
		bounce() {
			const fallback = '/pages/index/index'
			const target = this.redirect || fallback
			setTimeout(() => {
				if (target.startsWith('/pages/index')
					|| target.startsWith('/pages/feed')
					|| target.startsWith('/pages/component')
					|| target.startsWith('/pages/mine')) {
					uni.switchTab({ url: target, fail: () => uni.reLaunch({ url: target }) })
				} else {
					uni.reLaunch({ url: target })
				}
			}, 300)
		},
		async onSubmit() {
			if (this.submitting) return
			const verdict = auditEnrollForm(this.form)
			if (!verdict.ok) {
				if (verdict.field === 'accepted') this.flashPledge()
				if (verdict.field === 'passcode') this.passcodeAlert = true
				this.toast(this.$t(verdict.errorKey))
				return
			}
			this.submitting = true
			uni.showLoading({ title: this.copy.submitting, mask: true })
			try {
				await enrollAccount({
					handset: this.form.handset,
					region: this.region,
					secret: this.form.secret,
					passcode: this.form.passcode,
					ticketId: this.ticketId
				})
				try {
					const session = await sessionByCredential({
						account: this.form.handset,
						secret: this.form.secret,
						ticketId: this.ticketId
					})
					if (session) {
						this.$store.dispatch('user/login', session)
						this.$store.dispatch('cart/sync')
					}
					this.toast(this.$t('passport.tip-enroll-ok'))
					this.bounce()
				} catch (_) {
					this.toast(this.$t('passport.tip-enroll-need-login'))
					setTimeout(() => uni.redirectTo({ url: '/pages/passport/signin?mode=secret' }), 600)
				}
			} catch (err) {
				this.passcodeAlert = true
				this.toast((err && err.message) || this.$t('passport.tip-enroll-failed'))
			} finally {
				this.submitting = false
				uni.hideLoading()
			}
		}
	}
}
</script>

<style lang="scss">
.pp-enroll-steps {
	display: flex;
	margin-bottom: 36rpx;
}

.pp-enroll-steps__node {
	flex: 1;
	display: flex;
	flex-direction: column;
	align-items: center;
	position: relative;
}

.pp-enroll-steps__bubble {
	width: 56rpx;
	height: 56rpx;
	border-radius: 28rpx;
	background: rgba(255, 255, 255, 0.1);
	border: 2rpx solid rgba(255, 255, 255, 0.2);
	display: flex;
	align-items: center;
	justify-content: center;
	margin-bottom: 10rpx;
}

.pp-enroll-steps__num {
	font-size: 24rpx;
	color: rgba(255, 255, 255, 0.6);
	font-weight: 700;
}

.pp-enroll-steps__label {
	font-size: 22rpx;
	color: rgba(255, 255, 255, 0.55);
}

.pp-enroll-steps__bar {
	position: absolute;
	top: 28rpx;
	right: -42%;
	width: 84%;
	height: 4rpx;
	background: rgba(255, 255, 255, 0.18);
}

.pp-enroll-steps__node--on .pp-enroll-steps__bubble {
	background: linear-gradient(135deg, #ffb547, #ff4d6a);
	border-color: transparent;
	box-shadow: 0 14rpx 32rpx rgba(255, 181, 71, 0.4);
}

.pp-enroll-steps__node--on .pp-enroll-steps__num,
.pp-enroll-steps__node--done .pp-enroll-steps__num {
	color: #1a1f3b;
}

.pp-enroll-steps__node--done .pp-enroll-steps__bubble {
	background: linear-gradient(135deg, rgba(61, 90, 254, 0.9), rgba(125, 60, 252, 0.9));
	border-color: transparent;
}

.pp-enroll-steps__node--done .pp-enroll-steps__num {
	color: #fff;
}

.pp-enroll-steps__node--on .pp-enroll-steps__label,
.pp-enroll-steps__node--done .pp-enroll-steps__label {
	color: #fff;
}

.pp-enroll-field {
	margin-bottom: 28rpx;
}

.pp-enroll-field__head {
	display: flex;
	justify-content: space-between;
	align-items: center;
	margin-bottom: 16rpx;
}

.pp-enroll-field__label {
	display: block;
	color: rgba(255, 255, 255, 0.7);
	font-size: 24rpx;
	letter-spacing: 2rpx;
	margin-bottom: 16rpx;
}

.pp-enroll-field__head .pp-enroll-field__label {
	margin-bottom: 0;
}

.pp-enroll-field__hint {
	color: #ffb547;
	font-size: 24rpx;
}

.pp-enroll-field__hint--off {
	color: rgba(255, 255, 255, 0.4);
}

.pp-enroll-field__row {
	display: flex;
	align-items: stretch;
}

.pp-enroll-input {
	height: 96rpx;
	background: rgba(255, 255, 255, 0.08);
	border: 1rpx solid rgba(255, 255, 255, 0.16);
	padding: 0 28rpx;
	font-size: 30rpx;
	color: #fff;
	box-sizing: border-box;
	border-radius: 24rpx;
}

.pp-enroll-input--handset {
	flex: 1;
	border-radius: 0 24rpx 24rpx 0;
	border-left: none;
}

.pp-enroll-input--solo {
	display: flex;
	align-items: center;
	padding: 0 24rpx;
}

.pp-enroll-input__field {
	flex: 1;
	color: #fff;
	font-size: 30rpx;
	background: transparent;
	height: 100%;
}

.pp-enroll-input__placeholder {
	color: rgba(255, 255, 255, 0.35);
}

.pp-enroll-input__action {
	color: rgba(255, 255, 255, 0.7);
	font-size: 24rpx;
	padding: 12rpx 4rpx;
}

.pp-enroll-meter {
	display: flex;
	align-items: center;
	margin-top: 14rpx;
}

.pp-enroll-meter__bar {
	flex: 1;
	height: 6rpx;
	margin-right: 8rpx;
	border-radius: 6rpx;
	background: rgba(255, 255, 255, 0.16);
}

.pp-enroll-meter__bar--weak {
	background: #ff4d6a;
}

.pp-enroll-meter__bar--ok {
	background: #ffb547;
}

.pp-enroll-meter__bar--great {
	background: #25dc84;
}

.pp-enroll-meter__hint {
	margin-left: 12rpx;
	font-size: 22rpx;
	color: rgba(255, 255, 255, 0.55);
}

.pp-enroll-submit {
	width: 100%;
	height: 104rpx;
	margin-top: 12rpx;
	border-radius: 30rpx;
	background: linear-gradient(135deg, #3d5afe 0%, #6b3df0 50%, #ff4d6a 100%);
	border: none;
	box-shadow: 0 20rpx 60rpx rgba(61, 90, 254, 0.45);
	display: flex;
	align-items: center;
	justify-content: center;
}

.pp-enroll-submit::after {
	border: none;
}

.pp-enroll-submit--busy {
	opacity: 0.7;
}

.pp-enroll-submit__text {
	color: #fff;
	font-size: 32rpx;
	font-weight: 700;
	letter-spacing: 4rpx;
}

.pp-enroll-foot {
	display: flex;
	align-items: center;
	justify-content: center;
}

.pp-enroll-foot__text {
	color: rgba(255, 255, 255, 0.55);
	font-size: 24rpx;
}

.pp-enroll-foot__cta {
	color: #ffb547;
	font-size: 26rpx;
	font-weight: 700;
	margin-left: 12rpx;
	padding: 10rpx 16rpx;
	border-radius: 24rpx;
	background: rgba(255, 181, 71, 0.18);
}
</style>
