//
//  lichunWebsocketTests.swift
//  lichunWebsocketTests
//
//  Base test configuration and suite setup
//

import XCTest
@testable import lichunWebsocket

final class lichunWebsocketTests: XCTestCase {

    override func setUpWithError() throws {
        try super.setUpWithError()
        // Stop immediately when a failure occurs for easier debugging
        continueAfterFailure = false

        // Reset UserDefaults for clean test state
        UserDefaults.standard.removePersistentDomain(forName: Bundle.main.bundleIdentifier!)
        UserDefaults.standard.synchronize()
    }

    override func tearDownWithError() throws {
        // Clean up after each test
        try super.tearDown()
    }

    // MARK: - Basic Sanity Tests

    /// Test that the app bundle is valid
    func testAppBundleIsValid() throws {
        let bundle = Bundle(for: type(of: self))
        XCTAssertNotNil(bundle, "Test bundle should be valid")
        XCTAssertNotNil(Bundle.main.bundleIdentifier, "Main bundle should have identifier")
    }

    /// Test that key classes can be instantiated
    func testKeyClassesExist() throws {
        // Test that core classes exist and can be instantiated
        let analyticsManager = AnalyticsManager.shared
        XCTAssertNotNil(analyticsManager, "AnalyticsManager should be accessible")

        let toastManager = ToastManager.shared
        XCTAssertNotNil(toastManager, "ToastManager should be accessible")

        // Test model classes
        let person = Person()
        XCTAssertNotNil(person, "Person model should be instantiable")

        let player = Player()
        XCTAssertNotNil(player, "Player model should be instantiable")
    }

    /// Test that UserDefaults works correctly
    func testUserDefaultsWorking() throws {
        // Given: A test key-value pair
        let testKey = "test_key"
        let testValue = "test_value"

        // When: Storing to UserDefaults
        UserDefaults.standard.set(testValue, forKey: testKey)
        UserDefaults.standard.synchronize()

        // Then: Value should be retrievable
        let retrievedValue = UserDefaults.standard.string(forKey: testKey)
        XCTAssertEqual(retrievedValue, testValue, "UserDefaults should store and retrieve values correctly")

        // Clean up
        UserDefaults.standard.removeObject(forKey: testKey)
    }

    // MARK: - Model Tests

    /// Test Person model initialization
    func testPersonModelInitialization() throws {
        // Given: A new Person instance
        let person = Person()

        // Then: Should have default values
        XCTAssertEqual(person.id, "")
        XCTAssertEqual(person.firstname, "")
        XCTAssertEqual(person.ageYears, 0)
        XCTAssertEqual(person.calcEnergy, 0)
        XCTAssertEqual(person.money, 0)
        XCTAssertEqual(person.diamonds, 0)
    }

    /// Test Player model initialization
    func testPlayerModelInitialization() throws {
        // Given: A new Player instance
        let player = Player()

        // Then: Should have default values
        XCTAssertEqual(player.date, "")
        XCTAssertEqual(player.season, "")
        XCTAssertEqual(player.hourOfDay, 0)
        XCTAssertEqual(player.minuteOfHour, 0)
        XCTAssertTrue(player.activeConversations.isEmpty)
        XCTAssertTrue(player.r.isEmpty)
    }

    // MARK: - Helper Tests

    /// Test that test helpers work correctly
    func testTestHelpers() throws {
        // Test expectations work
        let expectation = XCTestExpectation(description: "Test expectation")

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
            expectation.fulfill()
        }

        wait(for: [expectation], timeout: 1.0)
        XCTAssertTrue(true, "Expectations should work correctly")
    }

    // MARK: - Performance Tests

    /// Test Person model creation performance
    func testPersonCreationPerformance() throws {
        measure {
            for _ in 0..<100 {
                let _ = Person()
            }
        }
    }

    /// Test Player model creation performance
    func testPlayerCreationPerformance() throws {
        measure {
            for _ in 0..<100 {
                let _ = Player()
            }
        }
    }
}

// MARK: - Test Utilities

extension XCTestCase {
    /// Wait for a condition to be true
    func wait(for condition: @autoclosure @escaping () -> Bool, timeout: TimeInterval = 5.0, message: String = "Condition not met") {
        let expectation = XCTestExpectation(description: message)

        let checkInterval: TimeInterval = 0.1
        var elapsed: TimeInterval = 0

        Timer.scheduledTimer(withTimeInterval: checkInterval, repeats: true) { timer in
            elapsed += checkInterval

            if condition() {
                expectation.fulfill()
                timer.invalidate()
            } else if elapsed >= timeout {
                timer.invalidate()
            }
        }

        wait(for: [expectation], timeout: timeout)
    }
}
