//
//  LoginViewModel.swift
//  suixinkan
//

import Foundation

/// 登录页 ViewModel，UI 状态与 Android `LoginViewModel` 对齐。
final class LoginViewModel {

    private(set) var account = ""
    private(set) var password = ""
    private(set) var isPrivacyChecked = false
    private(set) var enableRegister = false
    private(set) var isLoading = false
    private(set) var isSelectingAccount = false
    private(set) var pendingAccountSelection: AccountSelectionPayload?

    var isLoginEnabled: Bool {
        isValidPhone && !trimmedPassword.isEmpty
    }

    var trimmedPassword: String {
        password.trimmingCharacters(in: .whitespacesAndNewlines)
    }

    var normalizedUsername: String {
        normalizedPhoneNumber(account)
    }

    var isValidPhone: Bool {
        normalizedUsername.count == 11 && normalizedUsername.first == "1"
    }

    var onStateChange: (() -> Void)?

    /// 从本地存储恢复上次登录手机号与协议勾选状态。
    func applyStoredPreferences() {
        if account.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty,
           let lastUsername = AppStore.shared.session.lastLoginUsername {
            account = lastUsername
        }
        isPrivacyChecked = AppStore.shared.session.privacyAgreementAccepted
        notifyStateChange()
    }

    func updateAccount(_ value: String) {
        account = value
        notifyStateChange()
    }

    func updatePassword(_ value: String) {
        password = value
        notifyStateChange()
    }

    func togglePrivacyChecked() {
        isPrivacyChecked.toggle()
        notifyStateChange()
    }

    func updateEnableRegister(_ enabled: Bool) {
        enableRegister = enabled
        notifyStateChange()
    }

    /// 当输入包含 +86 前缀时，把手机号规范化为 11 位国内手机号。
    func normalizeUsernameCountryCodeIfNeeded() {
        let digits = account.filter(\.isNumber)
        let normalizedPhone = normalizedPhoneNumber(account)
        guard normalizedPhone != digits, normalizedPhone.count == 11 else { return }
        account = normalizedPhone
        notifyStateChange()
    }

    /// 校验登录表单，并返回第一个需要处理的错误。
    func validateForLogin() -> LoginValidationError? {
        guard isValidPhone else {
            return .invalidPhone
        }
        guard !trimmedPassword.isEmpty else {
            return .emptyPassword
        }
        guard isPrivacyChecked else {
            return .privacyUnchecked
        }
        return nil
    }

    func login() {
        if let error = validateForLogin() {
            onShowMessage?(error.message)
            return
        }
        onLogin?()
    }

    /// 加载 App 配置，控制验证码登录/注册入口显隐。
    func loadAppConfig(authAPI: AuthAPI) async {
        do {
            let config = try await authAPI.getAppConfig()
            updateEnableRegister(config.enableRegister)
        } catch {
            // 配置加载失败不影响密码登录，静默忽略。
        }
    }

    /// 发起登录，并根据账号数量决定直接完成或进入账号选择。
    func login(authAPI: AuthAPI) async throws -> LoginResolution {
        guard !isLoading else {
            throw CancellationError()
        }

        isLoading = true
        notifyStateChange()
        defer {
            isLoading = false
            notifyStateChange()
        }

        let response = try await authAPI.login(
            username: normalizedUsername,
            password: trimmedPassword
        )
        return try await resolveLoginResponse(response, authAPI: authAPI)
    }

    /// 选择一个账号并调用 set-user 换取正式 token。
    func selectAccount(_ account: AccountSwitchAccount, authAPI: AuthAPI) async throws -> V9AuthResponse {
        guard let payload = pendingAccountSelection, payload.hasTempToken else {
            throw LoginFlowError.missingToken
        }
        guard account.businessUserId > 0 else {
            throw LoginFlowError.invalidAccount
        }
        guard !isSelectingAccount else {
            throw CancellationError()
        }

        isSelectingAccount = true
        notifyStateChange()
        defer {
            isSelectingAccount = false
            notifyStateChange()
        }

        let response = try await authAPI.setUser(account.toSetUserRequest(), tokenOverride: payload.tempToken)
        guard !response.token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
            throw LoginFlowError.missingToken
        }
        pendingAccountSelection = nil
        notifyStateChange()
        return response
    }

    /// 清空待选账号信息，通常在用户取消账号选择时调用。
    func clearPendingAccountSelection() {
        pendingAccountSelection = nil
        notifyStateChange()
    }

    var onShowMessage: ((String) -> Void)?
    var onLogin: (() -> Void)?
    var onLoginByCode: (() -> Void)?
    var onRegister: (() -> Void)?
    var onUserAgreement: (() -> Void)?
    var onPrivacyPolicy: (() -> Void)?

    private func resolveLoginResponse(_ response: V9AuthResponse, authAPI: AuthAPI) async throws -> LoginResolution {
        let token = response.token.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !token.isEmpty else {
            throw LoginFlowError.missingToken
        }

        let accounts = response.accounts.filter { $0.businessUserId > 0 }
        guard !accounts.isEmpty else {
            throw LoginFlowError.noAvailableAccount
        }

        if accounts.count == 1, let account = accounts.first {
            let finalResponse = try await authAPI.setUser(account.toSetUserRequest(), tokenOverride: token)
            guard !finalResponse.token.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty else {
                throw LoginFlowError.missingToken
            }
            return .completed(finalResponse, account)
        }

        let payload = AccountSelectionPayload(tempToken: token, accounts: accounts)
        pendingAccountSelection = payload
        notifyStateChange()
        return .needsAccountSelection(payload)
    }

    private func normalizedPhoneNumber(_ value: String) -> String {
        var digits = value.filter(\.isNumber)
        if digits.hasPrefix("86"), digits.count == 13 {
            digits.removeFirst(2)
        }
        return digits
    }

    private func notifyStateChange() {
        onStateChange?()
    }
}
