//
//  LoginViewModelTests.swift
//  suixinkanTests
//

import XCTest
@testable import suixinkan

@MainActor
/// 登录页 ViewModel 测试，覆盖手机号规范化、表单校验和登录流程。
final class LoginViewModelTests: XCTestCase {
    func testNormalizeUsernameCountryCodeRemovesChinaPrefix() {
        let viewModel = LoginViewModel()
        viewModel.updateAccount("+86 186 5185 7230")

        viewModel.normalizeUsernameCountryCodeIfNeeded()

        XCTAssertEqual(viewModel.normalizedUsername, "18651857230")
        XCTAssertTrue(viewModel.isValidPhone)
    }

    func testIsLoginEnabledRequiresValidPhoneAndNonEmptyPassword() {
        let viewModel = LoginViewModel()
        viewModel.updateAccount("18651857230")
        viewModel.updatePassword(" secret123 ")

        XCTAssertTrue(viewModel.isLoginEnabled)
        XCTAssertEqual(viewModel.trimmedPassword, "secret123")
    }

    func testValidateForLoginReturnsExpectedErrorsInOrder() {
        let viewModel = LoginViewModel()
        viewModel.updateAccount("12345")
        viewModel.updatePassword("secret123")
        viewModel.togglePrivacyChecked()
        XCTAssertEqual(viewModel.validateForLogin(), .invalidPhone)

        viewModel.updateAccount("18651857230")
        viewModel.updatePassword("   ")
        XCTAssertEqual(viewModel.validateForLogin(), .emptyPassword)

        viewModel.updatePassword("secret123")
        viewModel.togglePrivacyChecked()
        XCTAssertEqual(viewModel.validateForLogin(), .privacyUnchecked)
    }

    func testLoginWithSingleAccountAutoCompletesSetUser() async throws {
        let loginJSON = """
        {
          "code": 100000,
          "msg": "success",
          "data": {
            "token": "temp-token",
            "scenic_users": [
              {
                "account_type": "scenic_user",
                "id": 101,
                "user_id": 101,
                "scenic_user_id": 101,
                "ss_user_id": 101,
                "username": "scenic_admin",
                "real_name": "张三",
                "nickname": "张三",
                "phone": "13800138000",
                "scenic_id": 10,
                "scenic_name": "示例景区",
                "is_current": false
              }
            ],
            "store_users": []
          }
        }
        """.data(using: .utf8)!

        let setUserJSON = """
        {
          "code": 100000,
          "msg": "success",
          "data": {
            "token": "business-token-scenic",
            "scenic_users": [],
            "store_users": []
          }
        }
        """.data(using: .utf8)!

        let session = MockURLSession(responses: [loginJSON, setUserJSON])
        let api = AuthAPI(client: APIClient(environment: .testing, session: session))
        let viewModel = LoginViewModel()
        viewModel.updateAccount("18651857230")
        viewModel.updatePassword("secret123")
        viewModel.togglePrivacyChecked()

        let resolution = try await viewModel.login(authAPI: api)

        guard case .completed(let response, let account) = resolution else {
            return XCTFail("单账号登录应直接完成")
        }
        XCTAssertEqual(response.token, "business-token-scenic")
        XCTAssertEqual(account.businessUserId, 101)
        XCTAssertFalse(viewModel.isLoading)
        XCTAssertNil(viewModel.pendingAccountSelection)
        XCTAssertEqual(session.requests.map { $0.url?.path }, [
            "/api/app/v9/login",
            "/api/app/v9/set-user",
        ])
    }

    func testLoginWithMultipleAccountsNeedsSelection() async throws {
        let loginJSON = """
        {
          "code": 100000,
          "msg": "success",
          "data": {
            "token": "person-temp-token",
            "scenic_users": [
              {
                "account_type": "scenic_user",
                "id": 101,
                "user_id": 101,
                "scenic_user_id": 101,
                "ss_user_id": 101,
                "username": "scenic_admin",
                "real_name": "张三",
                "nickname": "张三",
                "phone": "13800138000",
                "scenic_id": 10,
                "scenic_name": "示例景区",
                "is_current": false
              }
            ],
            "store_users": [
              {
                "account_type": "store_user",
                "id": 201,
                "user_id": 201,
                "store_user_id": 201,
                "username": "store_admin",
                "user_name": "store_admin",
                "real_name": "李四",
                "phone": "13900139000",
                "avatar": "",
                "scenic_id": 10,
                "scenic_name": "示例景区",
                "store_id": 20,
                "store_name": "示例门店",
                "is_current": false
              }
            ]
          }
        }
        """.data(using: .utf8)!

        let session = MockURLSession(responses: [loginJSON])
        let api = AuthAPI(client: APIClient(environment: .testing, session: session))
        let viewModel = LoginViewModel()
        viewModel.updateAccount("18651857230")
        viewModel.updatePassword("secret123")
        viewModel.togglePrivacyChecked()

        let resolution = try await viewModel.login(authAPI: api)

        guard case .needsAccountSelection(let payload) = resolution else {
            return XCTFail("多账号登录应进入账号选择")
        }
        XCTAssertEqual(payload.tempToken, "person-temp-token")
        XCTAssertEqual(payload.accounts.map(\.businessUserId), [101, 201])
        XCTAssertNotNil(viewModel.pendingAccountSelection)
        XCTAssertEqual(session.requests.count, 1)
    }

    func testLoginThrowsWhenNoAvailableAccounts() async {
        let loginJSON = """
        {
          "code": 100000,
          "msg": "success",
          "data": {
            "token": "person-temp-token",
            "scenic_users": [],
            "store_users": []
          }
        }
        """.data(using: .utf8)!

        let session = MockURLSession(responses: [loginJSON])
        let api = AuthAPI(client: APIClient(environment: .testing, session: session))
        let viewModel = LoginViewModel()
        viewModel.updateAccount("18651857230")
        viewModel.updatePassword("secret123")
        viewModel.togglePrivacyChecked()

        do {
            _ = try await viewModel.login(authAPI: api)
            XCTFail("没有可用账号时应抛出错误")
        } catch let error as LoginFlowError {
            guard case .noAvailableAccount = error else {
                return XCTFail("期望 noAvailableAccount，实际为 \(error)")
            }
        } catch {
            XCTFail("意外错误: \(error)")
        }
    }
}
