//
//  HomeMenuRouterTests.swift
//  suixinkanTests
//
//  Created by Codex on 2026/6/22.
//

import XCTest
@testable import suixinkan

/// 首页菜单路由测试，覆盖 URI 映射、别名和未知路由诊断。
final class HomeMenuRouterTests: XCTestCase {
    override func setUp() {
        super.setUp()
        HomeRouteDiagnostics.resetUnknownRoutes()
    }

    override func tearDown() {
        HomeRouteDiagnostics.resetUnknownRoutes()
        super.tearDown()
    }

    /// 测试已迁移的首页路由会解析到真实目标。
    func testMigratedRoutesResolveToDestinations() {
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "space_settings", title: ""), .destination(.profileSpace))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "scenicselection", title: ""), .destination(.scenicSelection))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "store", title: ""), .destination(.moreFunctions))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "wallet", title: ""), .destination(.wallet))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "payment_collection", title: ""), .destination(.paymentCollection))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "payment_qr", title: ""), .destination(.paymentCollection))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "payment_code", title: ""), .destination(.paymentCollection))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "permission_apply", title: ""), .destination(.permissionApply))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "permission_apply_status", title: ""), .destination(.permissionApplyStatus))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "scenicapplication", title: ""), .destination(.scenicApplication))
    }

    /// 测试已知但未迁移的首页路由会进入安全占位。
    func testKnownUnmigratedRoutesResolveToPlaceholders() {
        XCTAssertEqual(
            HomeMenuRouter.resolve(uri: "task_management", title: ""),
            .destination(.modulePlaceholder(uri: "task_management", title: "任务管理"))
        )
        XCTAssertEqual(
            HomeMenuRouter.resolve(uri: "scenic_settlement", title: ""),
            .destination(.modulePlaceholder(uri: "scenic_settlement", title: "景区结算"))
        )
        XCTAssertEqual(
            HomeMenuRouter.resolve(uri: "scenic_settlement_review", title: ""),
            .destination(.modulePlaceholder(uri: "scenic_settlement_review", title: "结算审核"))
        )
    }

    /// 测试 Tab 路由仍集中在 HomeMenuRouter。
    func testTabRoutesStayCentralized() {
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "photographer_orders", title: ""), .orders(.storeOrders))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "/scenic-order-manage", title: ""), .orders(.storeOrders))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "verification_order", title: ""), .orders(.verificationOrders))
        XCTAssertEqual(HomeMenuRouter.resolve(uri: "photographer_stats", title: ""), .tab(.statistics))
    }

    /// 测试飞控相关入口属于已知不支持范围。
    func testFlightControlRoutesAreKnownUnsupportedScope() {
        XCTAssertEqual(
            HomeMenuRouter.resolve(uri: "fly", title: ""),
            .unsupported(uri: "fly", title: "飞行管理", reason: "DJI/飞控模块已明确不纳入 iOS 迁移和后续开发范围。")
        )
    }

    /// 测试未知 URI 会显式进入 placeholder。
    func testUnknownRouteIsExplicitPlaceholder() {
        XCTAssertEqual(
            HomeMenuRouter.resolve(uri: "android_only_feature", title: "Android 专项"),
            .placeholder(uri: "android_only_feature", title: "Android 专项")
        )
    }

    /// 测试 canonicalURI 会使用当前权限可用的同义 URI。
    func testCanonicalURIUsesAvailableAlias() {
        let available: Set<String> = ["task_management_editor", "photographer_invite", "pm_manager", "payment_qr"]
        XCTAssertEqual(HomeMenuRouter.canonicalURI(for: "task_management", availableURIs: available), "task_management_editor")
        XCTAssertEqual(HomeMenuRouter.canonicalURI(for: "registration_invitation", availableURIs: available), "photographer_invite")
        XCTAssertEqual(HomeMenuRouter.canonicalURI(for: "pm", availableURIs: available), "pm_manager")
        XCTAssertEqual(HomeMenuRouter.canonicalURI(for: "payment_code", availableURIs: available), "payment_qr")
    }

    /// 测试 menuAliasKey 会把同义入口分到同一组。
    func testMenuAliasKeyGroupsDuplicateAndroidEntries() {
        XCTAssertEqual(HomeMenuRouter.menuAliasKey(for: "task_management_editor"), "task_management")
        XCTAssertEqual(HomeMenuRouter.menuAliasKey(for: "photographer_invite"), "registration_invitation")
        XCTAssertEqual(HomeMenuRouter.menuAliasKey(for: "pm_manager"), "pm")
        XCTAssertEqual(HomeMenuRouter.menuAliasKey(for: "payment_code"), "payment_collection")
        XCTAssertEqual(HomeMenuRouter.menuAliasKey(for: "deposit_order_shooting_info"), "deposit_order")
        XCTAssertEqual(HomeMenuRouter.menuAliasKey(for: "/scenic-order-manage"), "photographer_orders")
        XCTAssertEqual(HomeMenuRouter.menuAliasKey(for: "android_only_module"), "android_only_module")
    }

    /// 测试未知路由诊断会去重并更新标题。
    func testUnknownRouteDiagnosticsDeduplicatesAndUpdatesTitle() {
        HomeRouteDiagnostics.recordUnknown(uri: "android_feature", title: "旧标题")
        HomeRouteDiagnostics.recordUnknown(uri: "android_feature", title: "新标题")
        HomeRouteDiagnostics.recordUnknown(uri: "another_feature", title: "")

        let records = HomeRouteDiagnostics.unknownRoutes()

        XCTAssertEqual(records.count, 2)
        XCTAssertEqual(records.first { $0.uri == "android_feature" }?.title, "新标题")
        XCTAssertEqual(records.first { $0.uri == "android_feature" }?.count, 2)
        XCTAssertEqual(records.first { $0.uri == "another_feature" }?.count, 1)
    }

    /// 测试未知路由诊断报告是 Markdown 且按出现次数排序。
    func testUnknownRouteDiagnosticsReportIsMarkdownAndSortedByCount() {
        HomeRouteDiagnostics.recordUnknown(uri: "rare_feature", title: "低频入口")
        HomeRouteDiagnostics.recordUnknown(uri: "hot_feature", title: "高频入口")
        HomeRouteDiagnostics.recordUnknown(uri: "hot_feature", title: "高频入口")

        let report = HomeRouteDiagnostics.unknownRouteReport(generatedAt: Date(timeIntervalSince1970: 0))

        XCTAssertTrue(report.contains("# Home Route Diagnostics"))
        XCTAssertTrue(report.contains("| hot_feature | 高频入口 | 2 |"))
        XCTAssertLessThan(
            report.range(of: "hot_feature")!.lowerBound,
            report.range(of: "rare_feature")!.lowerBound
        )
    }

    /// 测试权限路由审计会区分可路由、不支持和未知入口。
    func testPermissionRouteAuditSeparatesRoutableUnsupportedAndUnknownEntries() {
        let permissions = [
            rolePermission(
                roleId: 1,
                permissions: [
                    permission(id: 1, name: "任务管理", uri: "task_management", children: [
                        permission(id: 2, name: "发布任务", uri: "task_create")
                    ]),
                    permission(id: 3, name: "飞控", uri: "pilot_controller"),
                    permission(id: 4, name: "Android 专项入口", uri: "android_only_module"),
                    permission(id: 5, name: "重复任务", uri: "task_management")
                ]
            )
        ]

        let audit = HomePermissionRouteAuditor.audit(permissions: permissions, currentRoleId: 1)

        XCTAssertEqual(audit.routable.map(\.uri), ["task_management", "task_create"])
        XCTAssertEqual(audit.unsupported.map(\.uri), ["pilot_controller"])
        XCTAssertEqual(audit.unknown.map(\.uri), ["android_only_module"])
        XCTAssertTrue(audit.hasUnknownRoutes)
    }

    /// 创建角色权限测试实体。
    private func rolePermission(roleId: Int, permissions: [PermissionItem]) -> RolePermissionResponse {
        RolePermissionResponse(
            role: RoleInfo(id: roleId, name: "角色\(roleId)", permission: permissions),
            scenic: []
        )
    }

    /// 创建权限节点测试实体。
    private func permission(id: Int, name: String, uri: String, children: [PermissionItem] = []) -> PermissionItem {
        PermissionItem(id: id, name: name, uri: uri, children: children)
    }
}
