<template>
	<view class="page-root">
		<ProfilePage
			v-if="showProfilePage"
			@open-settings="openSettings"
			@go-home="showProfilePage = false"
		/>
		<ConfigPage
			v-if="showConfigPage"
			v-show="!showProfilePage"
			@open-profile="showProfilePage = true"
		/>
		<view v-if="!showConfigPage && !showProfilePage" class="auth-page">
			<view class="auth-container">
				<view class="header">
					<image
						class="logo"
						mode="aspectFit"
						src="/static/logo.png"
					/>
					<text class="title">临床思维训练</text>
					<text class="subtitle">提升临床决策能力的高效平台</text>
				</view>

				<view class="form">
					<view class="form-group">
						<text class="label">手机号码</text>
						<view class="input-wrap" :class="{ focused: activeField === 'phone' }">
							<text class="country-code">+86</text>
							<view class="separator"></view>
							<input
								class="input"
								type="number"
								maxlength="11"
								v-model="form.phone"
								placeholder="请输入手机号"
								placeholder-class="placeholder"
								@focus="activeField = 'phone'"
								@blur="activeField = ''"
								@confirm="handleLogin"
							/>
						</view>
					</view>

					<view class="form-group">
						<text class="label">验证码</text>
						<view class="code-row">
							<view class="input-wrap code-input-wrap" :class="{ focused: activeField === 'code' }">
								<view class="verified-icon" aria-hidden="true"></view>
								<input
									class="input"
									type="number"
									maxlength="6"
									v-model="form.code"
									placeholder="短信验证码"
									placeholder-class="placeholder"
									@focus="activeField = 'code'"
									@blur="activeField = ''"
									@confirm="handleLogin"
								/>
							</view>
							<button
								class="code-button"
								:class="{ disabled: isCounting || sendingCode }"
								:disabled="isCounting || sendingCode"
								@click="handleSendCode"
							>
								{{ codeButtonText }}
							</button>
						</view>
					</view>

					<view class="form-group">
						<text class="label">所属机构</text>
						<view class="select-wrap" @click="institutionPickerVisible = true">
							<text class="select-text" :class="{ muted: !selectedInstitution }">
								{{ selectedInstitution ? selectedInstitution.name : '选择医院或医学院校' }}
							</text>
							<view class="select-arrow" aria-hidden="true"></view>
						</view>
					</view>

					<text class="hint">* 未注册手机号登录时将自动创建账号</text>

					<view class="login-area">
						<button class="login-button" :class="{ loading: submitting }" :disabled="submitting" @click="handleLogin">
							<view v-if="submitting" class="loading-spinner"></view>
							<text v-else>登录 / 注册</text>
						</button>
					</view>
				</view>

				<view class="footer">
					<view class="agreement" :class="{ shake: agreementShake }" @click="toggleAgreement">
						<view class="checkbox" :class="{ checked: agreed }"></view>
						<view class="agreement-copy">
							<text class="agreement-text">我已阅读并同意 </text>
							<text class="agreement-link" @click.stop="openAgreement('service')">《用户服务协议》</text>
							<text class="agreement-text"> 与 </text>
							<text class="agreement-link" @click.stop="openAgreement('privacy')">《隐私保护政策》</text>
						</view>
					</view>
				</view>
			</view>

			<view class="toast" :class="{ visible: toastVisible }">{{ toastMessage }}</view>

			<view v-if="institutionPickerVisible" class="picker-mask" @click="institutionPickerVisible = false">
				<view class="picker-panel" @click.stop>
					<view class="picker-header">
						<text class="picker-title">选择所属机构</text>
						<text class="picker-close" @click="institutionPickerVisible = false">关闭</text>
					</view>
					<scroll-view class="institution-list" scroll-y>
						<view v-if="institutionLoading" class="institution-empty">机构列表加载中...</view>
						<view v-else-if="institutions.length === 0" class="institution-empty">暂无可选机构</view>
						<view
							v-else
							v-for="institution in institutions"
							:key="institution.id"
							class="institution-item"
							:class="{ active: form.institutionId === institution.id }"
							@click="chooseInstitution(institution)"
						>
							<view class="institution-copy">
								<text class="institution-name">{{ institution.name }}</text>
								<text class="institution-meta">{{ institution.city }} · {{ institution.typeName }}</text>
							</view>
							<view v-if="form.institutionId === institution.id" class="selected-mark"></view>
						</view>
					</scroll-view>
				</view>
			</view>
		</view>
	</view>
</template>

<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, reactive, ref } from 'vue'
import { ApiRequestError, fetchInstitutions, loginWithCode, sendLoginCode, type InstitutionRecord } from '../../api/auth'
import ConfigPage from '../config/config.vue'
import ProfilePage from '../profile/profile.vue'

type Institution = {
	id: string
	code: string
	name: string
	city: string
	typeName: string
}

const institutions = ref<Institution[]>([])

const form = reactive({
	phone: '',
	code: '',
	institutionId: ''
})

const activeField = ref('')
const agreed = ref(false)
const agreementShake = ref(false)
const sendingCode = ref(false)
const submitting = ref(false)
const countdown = ref(0)
const toastMessage = ref('')
const toastVisible = ref(false)
const showConfigPage = ref(false)
const showProfilePage = ref(false)
const institutionPickerVisible = ref(false)
const institutionLoading = ref(false)
const institutionLoaded = ref(false)

let countdownTimer: ReturnType<typeof setInterval> | null = null
let toastTimer: ReturnType<typeof setTimeout> | null = null

const selectedInstitution = computed(() => {
	return institutions.value.find(item => item.id === form.institutionId)
})

const isCounting = computed(() => countdown.value > 0)

const codeButtonText = computed(() => {
	if (sendingCode.value) return '发送中...'
	return isCounting.value ? `${countdown.value}s` : '获取验证码'
})

function chooseInstitution(institution: Institution) {
	form.institutionId = institution.id
	institutionPickerVisible.value = false
}

function normalizeInstitution(item: InstitutionRecord): Institution {
	const typeNameMap: Record<string, string> = {
		hospital: '医院',
		college: '医学院校',
		school: '学校',
		clinic: '诊所'
	}
	const region = [item.province, item.city].filter(Boolean).join(' · ')
	return {
		id: String(item.id),
		code: item.code,
		name: item.name,
		city: region || '其他',
		typeName: typeNameMap[item.type] || '机构'
	}
}

async function loadInstitutions() {
	institutionLoading.value = true
	try {
		const result = await fetchInstitutions()
		institutions.value = result.map(normalizeInstitution)
	} catch (error) {
		showToast(error instanceof Error ? error.message : '机构列表加载失败')
		institutions.value = []
	} finally {
		institutionLoading.value = false
		institutionLoaded.value = true
	}
}

function toggleAgreement() {
	agreed.value = !agreed.value
}

async function handleSendCode() {
	if (sendingCode.value || isCounting.value) return
	if (!validatePhone()) return

	sendingCode.value = true
	try {
		let result
		try {
			result = await sendLoginCode(form.phone)
		} catch (error) {
			if (error instanceof ApiRequestError && error.code === 'AUTH_PHONE_NOT_FOUND') {
				result = await sendLoginCode(form.phone, 'register')
			} else {
				throw error
			}
		}
		showToast(result.message || '验证码已发送')
		startCountdown()
	} catch (error) {
		showToast(error instanceof Error ? error.message : '验证码发送失败')
	} finally {
		sendingCode.value = false
	}
}

onMounted(() => {
	void loadInstitutions()
})

function handleLogin() {
	if (submitting.value) return
	if (!validatePhone()) return
	if (!form.code.trim()) {
		showToast('请输入短信验证码')
		return
	}
	if (!selectedInstitution.value) {
		showToast('请选择所属机构')
		return
	}
	if (!agreed.value) {
		showToast('请阅读并勾选用户协议')
		triggerAgreementShake()
		return
	}

	submitting.value = true
	loginWithCode({
		phone: form.phone,
		code: form.code,
		institution_code: selectedInstitution.value.code,
		institution_name: selectedInstitution.value.name
	}).then(result => {
		const backendUser = result.user || {}
		const normalizedUser = {
			...backendUser,
			id: backendUser.id ? String(backendUser.id) : '',
			phone: backendUser.phone || form.phone,
			institutionId: selectedInstitution.value?.code || '',
			institutionCode: selectedInstitution.value?.code || '',
			institutionName: selectedInstitution.value?.name || ''
		}

		uni.setStorageSync('clinical-thinking-user', normalizedUser)
		uni.setStorageSync('clinical-thinking-tokens', result.tokens)
		uni.setStorageSync('clinical-thinking-access-token', result.tokens.access)
		uni.setStorageSync('clinical-thinking-refresh-token', result.tokens.refresh)
		showToast(result.message || '正在进入系统...')

		if (isFirstProfileSetup(backendUser.department)) {
			uni.redirectTo({
				url: '/pages/config/config'
			})
			return
		}

		uni.reLaunch({
			url: '/pages/home/home'
		})
	}).catch(error => {
		showToast(error instanceof Error ? error.message : '登录失败，请稍后重试')
	}).finally(() => {
		submitting.value = false
	})
}

function startCountdown() {
	countdown.value = 60
	clearCountdownTimer()
	countdownTimer = setInterval(() => {
		countdown.value -= 1
		if (countdown.value <= 0) {
			clearCountdownTimer()
		}
	}, 1000)
}

function validatePhone() {
	if (!/^1[3-9]\d{9}$/.test(form.phone)) {
		showToast('请输入正确的手机号')
		return false
	}
	return true
}

function isFirstProfileSetup(department: unknown) {
	if (department === null || department === undefined) return true
	if (typeof department === 'string') return department.trim() === ''
	if (Array.isArray(department)) return department.length === 0
	if (typeof department === 'object') return Object.keys(department).length === 0
	return false
}

function openAgreement(type: 'service' | 'privacy') {
	uni.showModal({
		title: type === 'service' ? '用户服务协议' : '隐私保护政策',
		content: '这里是前端模拟协议内容，后续可替换为正式协议页面或富文本接口。',
		showCancel: false,
		confirmColor: '#00478d'
	})
}

function openSettings() {
	showProfilePage.value = false
	showConfigPage.value = true
}

function triggerAgreementShake() {
	agreementShake.value = false
	nextTick(() => {
		agreementShake.value = true
		setTimeout(() => {
			agreementShake.value = false
		}, 500)
	})
}

function showToast(message: string) {
	if (toastTimer) clearTimeout(toastTimer)
	toastMessage.value = message
	toastVisible.value = true
	toastTimer = setTimeout(() => {
		toastVisible.value = false
	}, 2500)
}

function clearCountdownTimer() {
	if (countdownTimer) {
		clearInterval(countdownTimer)
		countdownTimer = null
	}
}

onUnmounted(() => {
	clearCountdownTimer()
	if (toastTimer) clearTimeout(toastTimer)
})
</script>

<style>
page {
	min-height: 100%;
	background: #f9f9ff;
}

.page-root {
	min-height: 100vh;
	background: #f9f9ff;
}

.auth-page {
	min-height: 100vh;
	background: #f9f9ff;
	color: #191c21;
	font-family: Inter, -apple-system, BlinkMacSystemFont, 'PingFang SC', 'Helvetica Neue', Arial, sans-serif;
	-webkit-tap-highlight-color: transparent;
}

.auth-container {
	box-sizing: border-box;
	width: 100%;
	max-width: 448px;
	min-height: 100vh;
	margin: 0 auto;
	padding: 32px 20px 24px;
	display: flex;
	flex-direction: column;
}

.header {
	margin: 24px 0;
	display: flex;
	flex-direction: column;
	align-items: center;
	text-align: center;
}

.logo {
	width: 96px;
	height: 96px;
	margin-bottom: 16px;
}

.title {
	color: #00478d;
	font-size: 24px;
	line-height: 32px;
	font-weight: 600;
	letter-spacing: 0;
}

.subtitle {
	margin-top: 8px;
	color: #727783;
	font-size: 14px;
	line-height: 20px;
	font-weight: 600;
	letter-spacing: 0;
}

.form {
	flex: 1;
}

.form-group {
	margin-bottom: 16px;
}

.label {
	display: block;
	margin: 0 0 8px 4px;
	color: #424752;
	font-size: 12px;
	line-height: 16px;
	font-weight: 500;
	letter-spacing: 0;
}

.input-wrap,
.select-wrap {
	box-sizing: border-box;
	width: 100%;
	height: 56px;
	padding: 0 16px;
	border: 1px solid #c2c6d4;
	border-radius: 8px;
	background: #f9f9ff;
	display: flex;
	align-items: center;
	transition: border-color 0.18s ease, box-shadow 0.18s ease, transform 0.18s ease;
}

.input-wrap.focused,
.select-wrap:active {
	border-color: #00478d;
	box-shadow: 0 0 0 1px #00478d;
}

.country-code {
	margin-right: 4px;
	color: #191c21;
	font-size: 16px;
	line-height: 24px;
	font-weight: 400;
}

.separator {
	width: 1px;
	height: 24px;
	margin: 0 12px;
	background: #c2c6d4;
}

.input {
	flex: 1;
	min-width: 0;
	height: 54px;
	padding: 0;
	border: 0;
	background: transparent;
	color: #191c21;
	font-size: 16px;
	line-height: 24px;
}

.placeholder {
	color: rgba(114, 119, 131, 0.6);
}

.code-row {
	display: flex;
	align-items: center;
	column-gap: 8px;
}

.code-input-wrap {
	flex: 1;
	min-width: 0;
}

.verified-icon {
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	margin-right: 12px;
	background: center / 24px 24px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24' fill='none' stroke='%23727783' stroke-width='2.3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M12 3l7 3v5c0 4.5-3 7.8-7 10-4-2.2-7-5.5-7-10V6l7-3z'/%3E%3Cpath d='M9 12l2 2 4-4'/%3E%3C/svg%3E");
}

.code-button {
	box-sizing: border-box;
	flex: 0 0 auto;
	height: 56px;
	padding: 0 16px;
	border: 1px solid #00478d;
	border-radius: 8px;
	background: #f9f9ff;
	color: #00478d;
	font-size: 14px;
	line-height: 54px;
	font-weight: 600;
	white-space: nowrap;
	transition: opacity 0.18s ease, transform 0.18s ease, background 0.18s ease;
}

.code-button:active,
.login-button:active {
	transform: scale(0.98);
}

.code-button.disabled {
	opacity: 0.5;
}

.code-button::after,
.login-button::after {
	border: 0;
}

.select-wrap {
	position: relative;
	justify-content: space-between;
}

.select-text {
	flex: 1;
	min-width: 0;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
	color: #191c21;
	font-size: 16px;
	line-height: 24px;
}

.select-text.muted {
	color: rgba(114, 119, 131, 0.6);
}

.select-arrow {
	flex: 0 0 auto;
	width: 28px;
	height: 28px;
	margin-left: 12px;
	background: center / 28px 28px no-repeat url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='28' height='28' viewBox='0 0 24 24' fill='none' stroke='%23727783' stroke-width='2.4' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M7 8l5 5 5-5'/%3E%3Cpath d='M7 12l5 5 5-5'/%3E%3C/svg%3E");
}

.hint {
	display: block;
	padding: 4px 0;
	text-align: center;
	color: #727783;
	font-size: 12px;
	line-height: 16px;
	font-weight: 500;
	letter-spacing: 0;
}

.login-area {
	padding-top: 16px;
}

.login-button {
	width: 100%;
	height: 56px;
	border-radius: 8px;
	background: #00478d;
	box-shadow: 0 4px 12px rgba(0, 71, 141, 0.2);
	color: #ffffff;
	font-size: 20px;
	line-height: 56px;
	font-weight: 600;
	display: flex;
	align-items: center;
	justify-content: center;
	transition: background 0.18s ease, transform 0.18s ease, opacity 0.18s ease;
}

.login-button.loading {
	opacity: 0.9;
}

.loading-spinner {
	width: 24px;
	height: 24px;
	border: 3px solid rgba(255, 255, 255, 0.36);
	border-top-color: #ffffff;
	border-radius: 50%;
	animation: spin 1s linear infinite;
}

.footer {
	margin-top: 24px;
	padding-bottom: env(safe-area-inset-bottom);
	display: flex;
	justify-content: center;
}

.agreement {
	max-width: 280px;
	display: flex;
	align-items: flex-start;
}

.checkbox {
	position: relative;
	box-sizing: border-box;
	flex: 0 0 auto;
	width: 16px;
	height: 16px;
	margin-top: 4px;
	margin-right: 8px;
	border: 1px solid #c2c6d4;
	border-radius: 4px;
	background: #ffffff;
}

.checkbox.checked {
	border-color: #00478d;
	background: #00478d;
}

.checkbox.checked::after {
	content: '';
	position: absolute;
	left: 4px;
	top: 1px;
	width: 5px;
	height: 9px;
	border-right: 2px solid #ffffff;
	border-bottom: 2px solid #ffffff;
	transform: rotate(45deg);
}

.agreement-copy {
	flex: 1;
	font-size: 0;
	line-height: 0;
}

.agreement-text,
.agreement-link {
	font-size: 12px;
	line-height: 20px;
	font-weight: 500;
	letter-spacing: 0;
}

.agreement-text {
	color: #424752;
}

.agreement-link {
	color: #00478d;
}

.toast {
	position: fixed;
	left: 50%;
	bottom: 128px;
	z-index: 100;
	max-width: 320px;
	padding: 12px 24px;
	border-radius: 999px;
	background: #2e3037;
	color: #eff0f8;
	font-size: 14px;
	line-height: 20px;
	font-weight: 600;
	text-align: center;
	pointer-events: none;
	opacity: 0;
	transform: translate(-50%, 16px);
	transition: opacity 0.3s ease, transform 0.3s ease;
}

.toast.visible {
	opacity: 1;
	transform: translate(-50%, 0);
}

.picker-mask {
	position: fixed;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	z-index: 90;
	background: rgba(25, 28, 33, 0.38);
	display: flex;
	align-items: flex-end;
	justify-content: center;
}

.picker-panel {
	box-sizing: border-box;
	width: 100%;
	max-width: 448px;
	max-height: 72vh;
	padding: 16px 20px calc(16px + env(safe-area-inset-bottom));
	border-radius: 16px 16px 0 0;
	background: #ffffff;
	box-shadow: 0 -12px 30px rgba(25, 28, 33, 0.16);
}

.picker-header {
	height: 40px;
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.picker-title {
	color: #191c21;
	font-size: 18px;
	line-height: 28px;
	font-weight: 600;
}

.picker-close {
	color: #00478d;
	font-size: 14px;
	line-height: 20px;
	font-weight: 600;
}

.institution-list {
	max-height: calc(72vh - 72px);
	margin-top: 8px;
}

.institution-empty {
	padding: 20px 4px;
	color: #727783;
	font-size: 14px;
	line-height: 20px;
	text-align: center;
}

.institution-item {
	box-sizing: border-box;
	min-height: 64px;
	padding: 12px 4px;
	border-bottom: 1px solid #ecedf6;
	display: flex;
	align-items: center;
	justify-content: space-between;
}

.institution-item.active {
	color: #00478d;
}

.institution-copy {
	flex: 1;
	min-width: 0;
	padding-right: 16px;
	display: flex;
	flex-direction: column;
}

.institution-name {
	color: #191c21;
	font-size: 16px;
	line-height: 24px;
	font-weight: 500;
	overflow: hidden;
	text-overflow: ellipsis;
	white-space: nowrap;
}

.institution-item.active .institution-name {
	color: #00478d;
	font-weight: 600;
}

.institution-meta {
	margin-top: 2px;
	color: #727783;
	font-size: 12px;
	line-height: 18px;
}

.selected-mark {
	position: relative;
	flex: 0 0 auto;
	width: 18px;
	height: 18px;
	border-radius: 50%;
	background: #00478d;
}

.selected-mark::after {
	content: '';
	position: absolute;
	left: 6px;
	top: 3px;
	width: 5px;
	height: 9px;
	border-right: 2px solid #ffffff;
	border-bottom: 2px solid #ffffff;
	transform: rotate(45deg);
}

.shake {
	animation: shake 0.5s cubic-bezier(.36, .07, .19, .97) both;
}

@keyframes shake {
	10%,
	90% {
		transform: translate3d(-1px, 0, 0);
	}
	20%,
	80% {
		transform: translate3d(2px, 0, 0);
	}
	30%,
	50%,
	70% {
		transform: translate3d(-4px, 0, 0);
	}
	40%,
	60% {
		transform: translate3d(4px, 0, 0);
	}
}

@keyframes spin {
	from {
		transform: rotate(0deg);
	}
	to {
		transform: rotate(360deg);
	}
}
</style>
