//
//  HomeViewModel.swift
//  suixinkan
//

import Foundation

/// 首页 ViewModel，对齐 Android `HomeViewModel` 的权限、门店与位置逻辑。
final class HomeViewModel {

    /// 首页位置上报卡片固定提示文案。
    static let locationReportPromptText = "您已进入打卡范围"

    private(set) var currentScenicName = ""
    private(set) var currentAppRole: AppRoleCode?
    private(set) var commonMenus: [HomeMenuItem] = []
    private(set) var storeItem: StoreItem?
    private(set) var showPermissionDialog = false
    private(set) var showScenicDialog = false
    private(set) var showLocationTimeoutDialog = false
    private(set) var showOnlineStatusDialog = false
    private(set) var showLocationReportSuccessDialog = false
    private(set) var isMinimalTopRole = false
    private(set) var locationInfoText = HomeViewModel.locationReportPromptText
    private(set) var reportTimeText = ""
    private(set) var isLocationReporting = false
    private(set) var needsPermissionReload = false
    private(set) var unreadMessageCount = 0

    var onStateChange: (() -> Void)?
    var onShowMessage: ((String) -> Void)?

    let locationStateStore: HomeLocationStateStore
    let locationReportService: LocationReportService
    private let appStore: AppStore
    private let commonMenuStore: HomeCommonMenuStore
    private let locationProvider: any LocationProviding

    private var timeoutDialogTriggered = false
    private var dismissedLocationTimeoutDialog = false

    init(
        appStore: AppStore = .shared,
        locationStateStore: HomeLocationStateStore = .shared,
        commonMenuStore: HomeCommonMenuStore = HomeCommonMenuStore(),
        locationProvider: any LocationProviding = LocationProvider.shared
    ) {
        self.appStore = appStore
        self.locationStateStore = locationStateStore
        self.locationProvider = locationProvider
        self.locationReportService = LocationReportService(
            appStore: appStore,
            locationStateStore: locationStateStore,
            locationProvider: locationProvider
        )
        self.commonMenuStore = commonMenuStore
        self.locationStateStore.observe(self) { [weak self] in
            self?.notifyStateChange()
        }
    }

    deinit {
        locationStateStore.removeObserver(self)
    }

    var isOnline: Bool { locationStateStore.isOnline }
    var countdownDisplayText: String { locationStateStore.countdownDisplayText }
    var reminderMinutes: Int { locationStateStore.reminderMinutes }
    var hasUnreadMessages: Bool { unreadMessageCount > 0 }

    /// 首次进入首页时加载权限并恢复在线状态。
    func initialize(api: HomeAPI) async {
        locationStateStore.restoreStateIfNeeded()
        refreshLocalDisplayState()
        await loadPermissions(api: api, force: true)
    }

    /// 账号切换后标记需要重新拉取权限。
    func markNeedsPermissionReload() {
        needsPermissionReload = true
        unreadMessageCount = 0
    }

    /// 查询未读消息总数，成功时更新首页状态并返回 `true`。
    func refreshUnreadMessageStatus(api: any MessageCenterServing) async -> Bool {
        do {
            let response = try await api.unreadCount()
            unreadMessageCount = response.unreadCount
            notifyStateChange()
            return true
        } catch is CancellationError {
            return false
        } catch {
            // 查询失败时保留上一次状态，避免网络抖动导致红点错误消失。
            return false
        }
    }

    /// 使用已知的最新未读消息数量立即刷新首页状态。
    func updateUnreadMessageCount(_ count: Int) {
        unreadMessageCount = max(count, 0)
        notifyStateChange()
    }

    /// 查询待审核记录并决定进入申请页或审核状态页。
    func resolvePermissionApplyDestination(api: HomeAPI) async -> PermissionApplyDestination {
        do {
            let pendingList = try await api.roleApplyPending()
            guard let first = pendingList.first,
                  first.status == PermissionApplyPendingStatus.reviewing
                    || first.status == PermissionApplyPendingStatus.rejected else {
                return .apply
            }
            return .status(applyCode: first.code)
        } catch {
            return .apply
        }
    }

    /// 按需重新拉取权限。
    func reloadIfNeeded(api: HomeAPI) async {
        locationStateStore.restoreStateIfNeeded()
        guard needsPermissionReload else {
            refreshLocalDisplayState()
            rebuildCommonMenus()
            await loadStoreListIfNeeded(api: api)
            notifyStateChange()
            return
        }
        needsPermissionReload = false
        await loadPermissions(api: api, force: true)
    }

    /// 拉取 role-permission 并刷新菜单。
    func loadPermissions(api: HomeAPI, force: Bool = false) async {
        if !force, !appStore.permissions.permissionItems().isEmpty {
            rebuildCommonMenus()
            await loadStoreListIfNeeded(api: api)
            notifyStateChange()
            return
        }

        do {
            let rolePermissionList = try await api.rolePermissions()
            if rolePermissionList.isEmpty {
                appStore.permissions.savePermissionItems([])
                showPermissionDialog = true
                rebuildCommonMenus()
                notifyStateChange()
                return
            }

            appStore.permissions.saveRolePermissionList(rolePermissionList)
            let matched = appStore.permissions.matchRolePermissionItem(in: rolePermissionList) ?? rolePermissionList[0]
            if !matched.role.roleCode.isEmpty {
                appStore.session.roleCode = matched.role.roleCode
            }
            if !matched.role.name.isEmpty {
                appStore.session.roleName = matched.role.name
            }
            appStore.permissions.saveRoleScenicList(matched.scenic)
            let permissions = matched.role.permission.map(HomePermissionItem.init)
            appStore.permissions.savePermissionItems(permissions)
            showPermissionDialog = false
            refreshLocalDisplayState()
            rebuildCommonMenus()
            await loadStoreListIfNeeded(api: api)
            notifyStateChange()
        } catch is CancellationError {
            return
        } catch {
            appStore.permissions.savePermissionItems([])
            showPermissionDialog = true
            rebuildCommonMenus()
            onShowMessage?(error.localizedDescription)
            notifyStateChange()
        }
    }

    /// 店铺管理员加载当前景区门店。
    func loadStoreListIfNeeded(api: HomeAPI) async {
        guard currentAppRole == .storeAdmin else {
            storeItem = nil
            notifyStateChange()
            return
        }
        guard appStore.session.currentScenicId > 0 else {
            storeItem = nil
            notifyStateChange()
            return
        }

        do {
            let response = try await api.storeList()
            let scenicId = appStore.session.currentScenicId
            let savedStoreId = appStore.session.currentStoreId
            let savedMatch = savedStoreId > 0 ? response.list.first { $0.id == savedStoreId } : nil
            let matched = savedMatch ?? response.list.first { $0.scenicId == scenicId }
            storeItem = matched
            if let matched {
                appStore.session.currentStoreId = matched.id
            }
            notifyStateChange()
        } catch is CancellationError {
            return
        } catch {
            storeItem = nil
            notifyStateChange()
        }
    }

    /// 评估弹窗展示优先级：权限 > 景区 > 位置超时。
    func evaluateDialogs(api: HomeAPI) async {
        if showPermissionDialog {
            showScenicDialog = false
            return
        }
        let hasScenic = appStore.session.currentScenicId > 0
        showScenicDialog = !hasScenic
        if showScenicDialog || dismissedLocationTimeoutDialog {
            showLocationTimeoutDialog = false
            notifyStateChange()
            return
        }
        guard !isMinimalTopRole else {
            showLocationTimeoutDialog = false
            notifyStateChange()
            return
        }
        try? await Task.sleep(nanoseconds: 500_000_000)
        await checkLocationTimeout(api: api)
    }

    /// 检查位置上报是否接近超时。
    func checkLocationTimeout(api: HomeAPI) async {
        guard reminderMinutes > 0 else {
            showLocationTimeoutDialog = false
            notifyStateChange()
            return
        }
        let staffId = appStore.session.userId.trimmingCharacters(in: .whitespacesAndNewlines)
        guard !staffId.isEmpty else {
            showLocationTimeoutDialog = true
            notifyStateChange()
            return
        }

        do {
            let detail = try await api.locationDetail(staffId: staffId)
            if detail.expireTime <= 0 {
                showLocationTimeoutDialog = true
                notifyStateChange()
                return
            }
            let currentMillis = Int64(Date().timeIntervalSince1970 * 1000)
            let expireMillis = detail.expireTime * 1000
            let threshold = expireMillis - Int64(reminderMinutes * 60 * 1000)
            showLocationTimeoutDialog = currentMillis >= threshold
            notifyStateChange()
        } catch is CancellationError {
            return
        } catch {
            showLocationTimeoutDialog = true
            notifyStateChange()
        }
    }

    /// 刷新景区名与角色展示状态，对齐 Android `initCurrentScenicName`。
    func refreshLocalDisplayState() {
        let scenicId = appStore.session.currentScenicId
        let scenicName = appStore.session.currentScenicName.trimmingCharacters(in: .whitespacesAndNewlines)
        if scenicId > 0, !scenicName.isEmpty {
            currentScenicName = scenicName
        } else {
            currentScenicName = ""
            appStore.session.currentScenicId = 0
            appStore.session.currentScenicName = ""
        }
        currentAppRole = appStore.session.currentAppRole
        isMinimalTopRole = currentAppRole?.usesHomeMinimalTopLayout ?? false
    }

    /// 重建常用应用列表。
    func rebuildCommonMenus() {
        let permissions = appStore.permissions.permissionItems()
        let allMenus = HomeMenuCatalog.visibleMenus(from: permissions)
        let accountScope = appStore.session.accountCachePrefix
        let roleCode = appStore.session.roleCode
        let savedURIs = commonMenuStore.savedCommonURIs(accountScope: accountScope, roleCode: roleCode)

        if savedURIs.isEmpty, !permissions.isEmpty {
            let defaultURIs = HomeCommonMenuStore.defaultCommonURIs(from: permissions)
            commonMenuStore.saveCommonURIs(defaultURIs, accountScope: accountScope, roleCode: roleCode)
        }

        commonMenus = commonMenuStore.commonMenus(
            from: allMenus,
            permissions: permissions,
            accountScope: accountScope,
            roleCode: roleCode
        )
    }

    func hidePermissionDialog() {
        showPermissionDialog = false
        notifyStateChange()
    }

    func hideScenicDialog() {
        showScenicDialog = false
        notifyStateChange()
    }

    func showOnlineStatusSwitchDialog() {
        showOnlineStatusDialog = true
        notifyStateChange()
    }

    func hideOnlineStatusSwitchDialog() {
        showOnlineStatusDialog = false
        notifyStateChange()
    }

    func hideLocationTimeoutDialog() {
        showLocationTimeoutDialog = false
        dismissedLocationTimeoutDialog = true
        timeoutDialogTriggered = false
        locationStateStore.updateOnlineStatus(false)
        notifyStateChange()
    }

    func hideLocationReportSuccessDialog() {
        showLocationReportSuccessDialog = false
        notifyStateChange()
    }

    func updateReminderMinutes(_ minutes: Int) {
        locationStateStore.updateReminderMinutes(minutes)
        notifyStateChange()
    }

    /// 切换在线/离线并触发位置上报。
    func switchOnlineStatus(api: HomeAPI) async {
        hideOnlineStatusSwitchDialog()
        isLocationReporting = true
        notifyStateChange()
        defer {
            isLocationReporting = locationReportService.isReporting
            notifyStateChange()
        }

        do {
            let goingOnline = !isOnline
            if let result = try await locationReportService.switchOnlineStatus(api: api) {
                applyReportSuccess(result)
                onShowMessage?(goingOnline ? "已切换到在线状态，正在上报位置" : "已切换到离线状态")
            } else {
                onShowMessage?("已切换到离线状态")
            }
            timeoutDialogTriggered = false
            dismissedLocationTimeoutDialog = false
        } catch let error as LocationReportServiceError {
            onShowMessage?(error.localizedDescription)
        } catch is CancellationError {
            return
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    /// 手动上报位置。
    func manualReportLocation(api: HomeAPI) async {
        isLocationReporting = true
        notifyStateChange()
        defer {
            isLocationReporting = locationReportService.isReporting
            notifyStateChange()
        }
        do {
            let result = try await locationReportService.manualReport(api: api)
            applyReportSuccess(result)
            onShowMessage?("位置上报成功")
        } catch let error as LocationReportServiceError {
            onShowMessage?(error.localizedDescription)
        } catch is CancellationError {
            return
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    /// 指定坐标上报（标记上报 type=2）。
    func reportLocation(
        api: HomeAPI,
        latitude: Double,
        longitude: Double,
        address: String?,
        type: Int
    ) async {
        isLocationReporting = true
        notifyStateChange()
        defer {
            isLocationReporting = locationReportService.isReporting
            notifyStateChange()
        }
        do {
            let result = try await locationReportService.reportWithCoordinates(
                api: api,
                latitude: latitude,
                longitude: longitude,
                address: address,
                type: type
            )
            applyReportSuccess(result)
            onShowMessage?("位置上报成功")
        } catch let error as LocationReportServiceError {
            onShowMessage?(error.localizedDescription)
        } catch is CancellationError {
            return
        } catch {
            onShowMessage?(error.localizedDescription)
        }
    }

    /// 位置超时弹窗确认上报。
    func confirmLocationTimeoutReport(api: HomeAPI) async {
        showLocationTimeoutDialog = false
        dismissedLocationTimeoutDialog = false
        await manualReportLocation(api: api)
    }

    /// 触发本地倒计时提醒。
    func triggerLocationTimeoutIfNeeded() {
        guard locationStateStore.shouldTriggerTimeoutReminder() else { return }
        guard !timeoutDialogTriggered else { return }
        timeoutDialogTriggered = true
        showLocationTimeoutDialog = true
        notifyStateChange()
    }

    /// 刷新当前位置文案。
    func refreshLocationInfo() async {
        isLocationReporting = true
        notifyStateChange()
        defer {
            isLocationReporting = false
            notifyStateChange()
        }
        do {
            let snapshot = try await locationProvider.requestSnapshot()
            locationInfoText = snapshot.address.isEmpty
                ? String(format: "%.5f, %.5f", snapshot.latitude, snapshot.longitude)
                : snapshot.address
        } catch {
            locationInfoText = "定位失败"
        }
    }

    private func applyReportSuccess(_ result: LocationReportSuccessResult) {
        locationInfoText = result.locationInfoText
        if result.shouldShowSuccessDialog {
            reportTimeText = result.reportTimeText
            showLocationReportSuccessDialog = true
            timeoutDialogTriggered = false
            dismissedLocationTimeoutDialog = false
        }
        notifyStateChange()
    }

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