//
//  HomeView.swift
//  suixinkan
//
//  Created by Codex on 2026/6/22.
//

import Combine
import SwiftUI

/// 首页主视图，展示景区、工作状态、快捷操作和权限菜单入口。
struct HomeView: View {
    @EnvironmentObject private var accountContext: AccountContext
    @EnvironmentObject private var permissionContext: PermissionContext
    @EnvironmentObject private var appRouter: AppRouter
    @EnvironmentObject private var router: RouterPath
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass

    @EnvironmentObject private var toastCenter: ToastCenter
    @EnvironmentObject private var homeLocationViewModel: HomeLocationViewModel
    @Environment(\.globalLoading) private var globalLoading
    @Environment(\.accountSnapshotStore) private var snapshotStore

    @StateObject private var viewModel = HomeViewModel()
    @State private var commonUris: [String] = []
    @State private var showOnlineDialog = false

    private let commonMenuStore = HomeCommonMenuStore()
    private let timer = Timer.publish(every: 1, on: .main, in: .common).autoconnect()

    private var contentMaxWidth: CGFloat {
        horizontalSizeClass == .regular ? 760 : .infinity
    }

    private var isStoreManager: Bool {
        permissionContext.currentAppRole?.isStoreAdmin == true
    }

    private var shouldShowWorkStatus: Bool {
        guard let role = permissionContext.currentAppRole else { return true }
        return !AppRoleCode.homeMinimalTopRoles.contains(role)
    }

    private var currentScenicName: String {
        accountContext.currentScenic?.name ?? "请选择景区"
    }

    private var countdownDisplay: String {
        homeLocationViewModel.countdownDisplay
    }

    private var reminderText: String {
        homeLocationViewModel.reminderMinutes == 0 ? "不提醒" : "提前\(homeLocationViewModel.reminderMinutes)分钟"
    }

    private var staffId: Int? {
        snapshotStore.load()?.businessUserId
    }

    private var scenicId: Int? {
        accountContext.currentScenic?.id
    }

    private var tileHeight: CGFloat {
        horizontalSizeClass == .regular ? 118 : 102
    }

    private var displayMenuItems: [HomeMenuItem] {
        let items = commonUris.compactMap(menuItemForHomeEntry(uri:))
        return items + [HomeMenuItem(title: "更多功能", uri: "more_functions", iconSrc: nil)]
    }

    var body: some View {
        VStack(spacing: 0) {
            topBar

            ScrollView {
                VStack(alignment: .leading, spacing: AppMetrics.Spacing.small) {
                    if shouldShowWorkStatus {
                        statusCard
                        locationReportCard
                        quickActionsRow
                    }

                    if isStoreManager, let store = accountContext.currentStore {
                        storeCard(store)
                            .padding(.bottom, AppMetrics.Spacing.xSmall)
                    }

                    Text("常用应用")
                        .font(.system(size: AppMetrics.FontSize.body, weight: .bold))
                        .foregroundStyle(Color(hex: 0x333333))
                        .padding(.top, shouldShowWorkStatus ? AppMetrics.Spacing.xxSmall : AppMetrics.Spacing.xSmall)
                        .padding(.bottom, AppMetrics.Spacing.xxSmall)

                    appGrid
                }
                .frame(maxWidth: contentMaxWidth, alignment: .topLeading)
                .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
                .padding(.top, AppMetrics.Spacing.xxLarge)
                .padding(.bottom, AppMetrics.Spacing.pageVertical)
                .frame(maxWidth: .infinity)
            }
            .background(Color(hex: 0xF5F5F5))
        }
        .background(Color(hex: 0xF5F5F5).ignoresSafeArea())
        .toolbar(.hidden, for: .navigationBar)
        .task {
            rebuildMenusFromCurrentContext()
            homeLocationViewModel.restoreState()
            await homeLocationViewModel.checkLocationTimeout(staffId: staffId)
        }
        .onReceive(timer) { _ in
            homeLocationViewModel.tick()
        }
        .onChange(of: permissionContext.currentRole?.roleCode) { _ in
            rebuildMenusFromCurrentContext()
        }
        .onChange(of: permissionContext.rolePermissions.count) { _ in
            rebuildMenusFromCurrentContext()
        }
        .alert("切换在线状态", isPresented: $showOnlineDialog) {
            Button("取消", role: .cancel) {}
            Button("确定") {
                runLocationReportTask {
                    await homeLocationViewModel.confirmOnlineToggle(
                        staffId: staffId,
                        scenicId: scenicId,
                        toast: toastCenter
                    )
                }
            }
        } message: {
            Text(homeLocationViewModel.isOnline ? "是否确认切换为离线状态？离线后将暂停位置上报。" : "是否确认切换为在线状态？在线后将开始位置上报和计时。")
        }
        .alert("位置上报提醒", isPresented: $homeLocationViewModel.showReminderDialog) {
            Button("立即上报") {
                homeLocationViewModel.dismissReminderDialog()
                runLocationReportTask {
                    await homeLocationViewModel.startImmediateReport(
                        staffId: staffId,
                        scenicId: scenicId,
                        toast: toastCenter
                    )
                }
            }
            Button("稍后", role: .cancel) {
                homeLocationViewModel.dismissReminderDialog()
            }
        } message: {
            Text(homeLocationViewModel.reminderDialogMessage)
        }
        .alert("位置上报超时", isPresented: $homeLocationViewModel.showTimeoutDialog) {
            Button("立即上报") {
                homeLocationViewModel.showTimeoutDialog = false
                runLocationReportTask {
                    await homeLocationViewModel.startImmediateReport(
                        staffId: staffId,
                        scenicId: scenicId,
                        toast: toastCenter
                    )
                }
            }
            Button("取消", role: .cancel) {
                homeLocationViewModel.dismissTimeoutDialog()
            }
        } message: {
            Text("位置上报即将超时或已超时，请立即重新上报。")
        }
    }

    private var topBar: some View {
        HStack {
            Button {
                router.navigate(to: .home(.scenicSelection))
            } label: {
                HStack(spacing: AppMetrics.Spacing.xSmall) {
                    Text(currentScenicName)
                        .font(.system(size: AppMetrics.FontSize.title3, weight: .semibold))
                        .foregroundStyle(Color(hex: 0x333333))
                        .lineLimit(1)
                        .minimumScaleFactor(0.8)
                    Image(systemName: "chevron.down")
                        .font(.system(size: AppMetrics.FontSize.subheadline, weight: .bold))
                        .foregroundStyle(.black)
                }
                .frame(maxWidth: .infinity, alignment: .leading)
                .contentShape(Rectangle())
            }
            .buttonStyle(.plain)
        }
        .padding(.horizontal, AppMetrics.Spacing.pageHorizontal)
        .frame(height: 78)
        .background(.white)
    }

    private var statusCard: some View {
        HStack(spacing: AppMetrics.Spacing.small) {
            Button {
                showOnlineDialog = true
            } label: {
                Text(homeLocationViewModel.isOnline ? "在线" : "离线")
                    .font(.system(size: AppMetrics.FontSize.caption, weight: .medium))
                    .foregroundStyle(homeLocationViewModel.isOnline ? Color(hex: 0xF0FDF4) : Color(hex: 0x7B8EAA))
                    .padding(.horizontal, AppMetrics.Spacing.small)
                    .padding(.vertical, AppMetrics.Spacing.xxSmall + 2)
                    .background(homeLocationViewModel.isOnline ? Color(hex: 0x22C55E) : Color(hex: 0xF4F4F4), in: RoundedRectangle(cornerRadius: 4))
            }
            .buttonStyle(.plain)

            Spacer(minLength: AppMetrics.Spacing.xxSmall)

            Label {
                Text(countdownDisplay)
                    .font(.system(size: AppMetrics.FontSize.body, weight: .medium))
            } icon: {
                Image(systemName: "clock")
                    .font(.system(size: AppMetrics.FontSize.subheadline, weight: .medium))
            }
            .foregroundStyle(AppDesign.primary)
            .lineLimit(1)
            .minimumScaleFactor(0.85)

            Spacer(minLength: AppMetrics.Spacing.xxSmall)

            ReminderTimeOptionsMenu(onSelect: { homeLocationViewModel.updateReminderMinutes($0) }) {
                Label {
                    Text(reminderText)
                        .font(.system(size: AppMetrics.FontSize.body, weight: .medium))
                } icon: {
                    Image(systemName: "bell.fill")
                        .font(.system(size: AppMetrics.FontSize.subheadline, weight: .medium))
                }
                .foregroundStyle(AppDesign.primary)
                .lineLimit(1)
                .minimumScaleFactor(0.8)
            }
            .buttonStyle(.plain)
        }
        .padding(15)
        .frame(minHeight: 84)
        .frame(maxWidth: .infinity)
        .background(.white, in: RoundedRectangle(cornerRadius: 8))
    }

    private var locationReportCard: some View {
        HStack(spacing: AppMetrics.Spacing.medium) {
            VStack(alignment: .leading, spacing: AppMetrics.Spacing.xxSmall) {
                HStack(spacing: AppMetrics.Spacing.xSmall) {
                    Image(systemName: "arrow.up.square.fill")
                        .font(.system(size: 25, weight: .bold))
                        .foregroundStyle(AppDesign.primary)
                    Text("立即上报")
                        .font(.system(size: 22, weight: .bold))
                        .foregroundStyle(Color(hex: 0x333333))
                }

                Text("您已进入打卡范围")
                    .font(.system(size: 15))
                    .foregroundStyle(Color(hex: 0x999999))
            }

            Spacer()

            Button {
                runLocationReportTask {
                    await homeLocationViewModel.startImmediateReport(
                        staffId: staffId,
                        scenicId: scenicId,
                        toast: toastCenter
                    )
                }
            } label: {
                Image(systemName: "hand.tap.fill")
                    .font(.system(size: 38, weight: .semibold))
                    .foregroundStyle(.white)
                    .frame(width: 92, height: 92)
                    .background(
                        LinearGradient(
                            colors: [Color(hex: 0x0073FF), Color(hex: 0x5CA8FF)],
                            startPoint: .top,
                            endPoint: .bottom
                        ),
                        in: Circle()
                    )
            }
            .buttonStyle(.plain)
            .accessibilityLabel("上报位置")
        }
        .padding(15)
        .frame(minHeight: 132)
        .frame(maxWidth: .infinity)
        .background(.white, in: RoundedRectangle(cornerRadius: 8))
    }

    private var quickActionsRow: some View {
        HStack(spacing: AppMetrics.Spacing.small) {
            quickAction(icon: "qrcode", title: "立即收款") {
                openRoute(HomeMenuRouter.resolve(uri: "payment_collection", title: "立即收款"))
            }

            quickAction(icon: "checklist.checked", title: "提交任务") {
                openRoute(HomeMenuRouter.resolve(uri: "task_create", title: "提交任务"))
            }

            quickAction(icon: homeLocationViewModel.isOnline ? "wifi" : "wifi.slash", title: homeLocationViewModel.isOnline ? "在线" : "离线", active: homeLocationViewModel.isOnline) {
                showOnlineDialog = true
            }
        }
    }

    private func quickAction(icon: String, title: String, active: Bool = false, action: @escaping () -> Void) -> some View {
        Button(action: action) {
            VStack(spacing: AppMetrics.Spacing.xSmall) {
                Image(systemName: icon)
                    .font(.system(size: 30, weight: .semibold))
                    .foregroundStyle(AppDesign.primary)
                    .frame(height: 34)

                Text(title)
                    .font(.system(size: AppMetrics.FontSize.body))
                    .foregroundStyle(Color.black)
                    .lineLimit(1)
                    .minimumScaleFactor(0.8)
            }
            .frame(maxWidth: .infinity)
            .frame(height: tileHeight)
            .background(active ? Color(hex: 0xE3F2FD) : .white, in: RoundedRectangle(cornerRadius: 8))
        }
        .buttonStyle(.plain)
    }

    private func storeCard(_ store: BusinessScope) -> some View {
        HStack(alignment: .top, spacing: 14) {
            VStack(alignment: .leading, spacing: AppMetrics.Spacing.xSmall) {
                Text(store.name)
                    .font(.system(size: AppMetrics.FontSize.title2, weight: .bold))
                    .foregroundStyle(.black)
                    .lineLimit(1)

                if let scenic = accountContext.currentScenic {
                    Text(scenic.name)
                        .font(.system(size: AppMetrics.FontSize.subheadline))
                        .foregroundStyle(Color(hex: 0x7B8EAA))
                        .lineLimit(2)
                }
            }

            Spacer()

            Text("营业中")
                .font(.system(size: AppMetrics.FontSize.caption))
                .foregroundStyle(Color(hex: 0x22C55E))
                .padding(.horizontal, AppMetrics.Spacing.xSmall + 2)
                .padding(.vertical, AppMetrics.Spacing.xxxSmall)
                .background(Color(hex: 0xF0FDF4), in: RoundedRectangle(cornerRadius: 4))
        }
        .padding(AppMetrics.Spacing.medium)
        .frame(maxWidth: .infinity)
        .background(.white, in: RoundedRectangle(cornerRadius: 8))
    }

    private var appGrid: some View {
        LazyVGrid(columns: menuColumns, spacing: 15) {
            ForEach(displayMenuItems) { item in
                Button {
                    openMenu(item)
                } label: {
                    VStack(spacing: AppMetrics.Spacing.small) {
                        menuIconView(for: item)
                            .frame(width: 30, height: 30)
                        Text(item.title)
                            .font(.system(size: AppMetrics.FontSize.body))
                            .foregroundStyle(Color(hex: 0x4B5563))
                            .lineLimit(1)
                            .minimumScaleFactor(0.75)
                    }
                    .frame(maxWidth: .infinity)
                    .frame(height: tileHeight)
                    .background(.white, in: RoundedRectangle(cornerRadius: 8))
                }
                .buttonStyle(.plain)
            }
        }
    }

    private var menuColumns: [GridItem] {
        Array(repeating: GridItem(.flexible(), spacing: 15), count: 3)
    }

    @ViewBuilder
    private func menuIconView(for item: HomeMenuItem) -> some View {
        RemoteImage(urlString: item.iconSrc, contentMode: .fit) {
            fallbackMenuIcon(for: item.uri)
        }
    }

    private func fallbackMenuIcon(for uri: String) -> some View {
        Image(systemName: iconName(for: uri))
            .font(.system(size: 24, weight: .semibold))
            .foregroundStyle(AppDesign.primary)
            .frame(width: 30, height: 30)
    }

    private func iconName(for uri: String) -> String {
        HomeIconCatalog.iconName(for: uri)
    }

    private func menuItemForHomeEntry(uri: String) -> HomeMenuItem? {
        let availableURIs = Set(viewModel.menuItems.map(\.uri))
        let resolvedUri = HomeMenuRouter.canonicalURI(for: uri, availableURIs: availableURIs)
        guard let existing = viewModel.menuItems.first(where: { $0.uri == resolvedUri }) else {
            return nil
        }
        return HomeMenuItem(
            title: HomeMenuRouter.displayTitle(for: resolvedUri, fallback: existing.title),
            uri: resolvedUri,
            iconSrc: existing.iconSrc
        )
    }

    private func openMenu(_ item: HomeMenuItem) {
        openRoute(HomeMenuRouter.resolve(uri: item.uri, title: item.title))
    }

    private func openRoute(_ route: HomeMenuResolvedRoute) {
        switch route {
        case .tab(let tab):
            appRouter.select(tab)
        case .orders(let entry):
            appRouter.selectOrders(entry: entry)
        case .orderPush(let route):
            appRouter.select(.orders)
            appRouter.router(for: .orders).navigate(to: .orders(route))
        case .destination(let route):
            router.navigate(to: .home(route))
        case .unsupported(let uri, let title, _):
            router.navigate(to: .home(.modulePlaceholder(uri: uri, title: title)))
        case .placeholder(let uri, let title):
            HomeRouteDiagnostics.recordUnknown(uri: uri, title: title)
            router.navigate(to: .home(.modulePlaceholder(uri: uri, title: title)))
        }
    }

    private func rebuildMenusFromCurrentContext() {
        let roleCode = permissionContext.currentAppRole?.rawValue
        let legacyRoleId = permissionContext.currentRole?.id
        viewModel.buildMenus(
            from: permissionContext.rolePermissions,
            currentRoleCode: roleCode
        )
        commonUris = commonMenuStore.load(
            menuItems: viewModel.menuItems,
            roleCode: roleCode,
            accountScope: accountContext.accountCachePrefix,
            legacyRoleId: legacyRoleId,
            topLevelPermissionURIs: permissionContext.topLevelPermissionURIs(for: roleCode)
        )
        let displayItems = displayMenuItems.map { ($0.title, $0.uri) }
        HomeCommonMenuDiagnostics.log(
            step: "displayItems",
            fields: [
                "items": HomeCommonMenuDiagnostics.formatDisplayItems(displayItems)
            ]
        )
    }

    /// 包裹需要 GPS 定位的位置上报操作，定位期间展示全局 Loading。
    private func runLocationReportTask(_ body: @escaping () async -> Void) {
        Task {
            await globalLoading.withLoading(message: "获取定位中", showsMessage: true) {
                await body()
            }
        }
    }
}

#Preview {
    NavigationStack {
        HomeView()
            .environmentObject(AccountContext())
            .environmentObject(PermissionContext())
            .environmentObject(AppRouter())
            .environmentObject(RouterPath())
            .environmentObject(ToastCenter())
            .environmentObject(HomeLocationViewModel(api: LocationReportAPI(client: APIClient())))
            .environment(\.accountSnapshotStore, AccountSnapshotStore())
    }
}
