import XCTest
import Combine
@testable import PortfolioJournal

// Note: These tests require Core Data model access. Disabled by default.
@MainActor
final class SnapshotFormViewModelTests: XCTestCase {

    override class var defaultTestSuite: XCTestSuite {
        // Skip all tests in this class - Core Data is not available in test bundle
        return XCTestSuite(name: "SnapshotFormViewModelTests (Skipped - Core Data not available)")
    }

    var testStack: TestCoreDataStack?
    var cancellables: Set<AnyCancellable>!

    override func setUp() async throws {
        try await super.setUp()
        do {
            testStack = try TestCoreDataStack()
        } catch {
            testStack = nil
        }
        cancellables = []
    }

    override func tearDown() async throws {
        testStack?.reset()
        testStack = nil
        cancellables = nil
        try await super.tearDown()
    }

    /// Helper to skip test if Core Data is not available
    private func requireCoreData() throws -> TestCoreDataStack {
        guard let stack = testStack else {
            throw XCTSkip("Core Data is not available in this test environment")
        }
        return stack
    }

    // MARK: - Test Helpers

    private func createTestSource() throws -> InvestmentSource {
        let stack = try requireCoreData()
        let account = stack.createTestAccount(name: "Test Account", currency: "USD")
        let source = stack.createTestSource(name: "Test Source", account: account)
        try? stack.save()
        return source
    }

    // MARK: - Initialization Tests

    func testInit_setsCorrectCurrencySymbol() async throws {
        // Given
        let source = try createTestSource()

        // When
        let viewModel = SnapshotFormViewModel(source: source)

        // Then
        XCTAssertEqual(viewModel.currencySymbol, "$")
    }

    func testInit_inAddMode_hasEmptyValueString() async throws {
        // Given
        let source = try createTestSource()

        // When
        let viewModel = SnapshotFormViewModel(source: source, mode: .add)

        // Then
        XCTAssertEqual(viewModel.valueString, "")
    }

    // MARK: - Validation Tests

    func testValidation_withEmptyValue_isNotValid() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.valueString = ""

        // Then - wait for validation to propagate
        try? await Task.sleep(nanoseconds: 100_000_000) // 100ms
        XCTAssertFalse(viewModel.isValid)
    }

    func testValidation_withValidValue_isValid() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.valueString = "1000.00"

        // Then - wait for validation to propagate
        try? await Task.sleep(nanoseconds: 100_000_000)
        XCTAssertTrue(viewModel.isValid)
    }

    func testValidation_withNegativeValue_isNotValid() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.valueString = "-100"

        // Then
        try? await Task.sleep(nanoseconds: 100_000_000)
        XCTAssertFalse(viewModel.isValid)
    }

    func testValidation_withContributionEnabled_requiresValidContribution() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.valueString = "1000"
        viewModel.includeContribution = true
        viewModel.contributionString = ""

        // Then
        try? await Task.sleep(nanoseconds: 100_000_000)
        XCTAssertFalse(viewModel.isValid)
    }

    func testValidation_withValidContribution_isValid() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.valueString = "1000"
        viewModel.includeContribution = true
        viewModel.contributionString = "100"

        // Then
        try? await Task.sleep(nanoseconds: 100_000_000)
        XCTAssertTrue(viewModel.isValid)
    }

    // MARK: - Parsing Tests

    func testParsing_withUSFormat_parsesCorrectly() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.valueString = "1000.50"

        // Then
        XCTAssertEqual(viewModel.value, 1000.50)
    }

    func testParsing_withCommaDecimalSeparator_parsesCorrectly() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When - comma as decimal separator (European format)
        viewModel.valueString = "1000,50"

        // Then - should parse with fallback
        XCTAssertNotNil(viewModel.value)
    }

    func testParsing_withCurrencySymbol_stripsSymbol() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.valueString = "$1000.50"

        // Then
        XCTAssertNotNil(viewModel.value)
    }

    // MARK: - Title Tests

    func testTitle_inAddMode_returnsAddSnapshot() async throws {
        // Given
        let source = try createTestSource()

        // When
        let viewModel = SnapshotFormViewModel(source: source, mode: .add)

        // Then
        XCTAssertEqual(viewModel.title, "Add Snapshot")
    }

    // MARK: - Button Title Tests

    func testButtonTitle_inAddMode_returnsAddSnapshot() async throws {
        // Given
        let source = try createTestSource()

        // When
        let viewModel = SnapshotFormViewModel(source: source, mode: .add)

        // Then
        XCTAssertEqual(viewModel.buttonTitle, "Add Snapshot")
    }

    // MARK: - Previous Value Tests

    func testPreviousValue_withNoSnapshots_returnsNil() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When/Then
        XCTAssertNil(viewModel.previousValue)
    }

    func testPreviousValueString_withNoSnapshots_returnsNoPreviousValue() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When/Then
        XCTAssertEqual(viewModel.previousValueString, "No previous value")
    }

    // MARK: - Date Validation Tests

    func testIsDateInFuture_withCurrentDate_returnsFalse() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.date = Date()

        // Then
        XCTAssertFalse(viewModel.isDateInFuture)
    }

    func testIsDateInFuture_withFutureDate_returnsTrue() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.date = Date().adding(days: 1)

        // Then
        XCTAssertTrue(viewModel.isDateInFuture)
    }

    func testDateWarning_withFutureDate_returnsWarning() async throws {
        // Given
        let source = try createTestSource()
        let viewModel = SnapshotFormViewModel(source: source)

        // When
        viewModel.date = Date().adding(days: 1)

        // Then
        XCTAssertNotNil(viewModel.dateWarning)
        XCTAssertEqual(viewModel.dateWarning, "Date is in the future")
    }
}
