//
//  IntegrationTests.swift
//  ReflectTests
//
//  Integration tests verifying full lifecycle pipelines.
//

import XCTest
import SwiftData
@testable import Reflect

@MainActor
final class IntegrationTests: XCTestCase {
    var sut: DataController!

    override func setUp() {
        super.setUp()
        let schema = Schema([MoodEntryModel.self])
        let config = ModelConfiguration(schema: schema, isStoredInMemoryOnly: true)
        sut = DataController(container: try! ModelContainer(for: schema, configurations: [config]))
    }

    override func tearDown() {
        sut = nil
        super.tearDown()
    }

    // MARK: - Phase 8: Integration Pipelines

    func test_fullCRUD_lifecycle() {
        let date = makeDate(2024, 6, 15)

        // Create
        sut.add(mood: .good, forDate: date, entryType: .listView)
        XCTAssertNotNil(sut.getEntry(byDate: date))

        // Read
        let entry = sut.getEntry(byDate: date)
        XCTAssertEqual(entry?.mood, .good)

        // Update
        let updated = sut.update(entryDate: date, withMood: .great)
        XCTAssertTrue(updated)
        XCTAssertEqual(sut.getEntry(byDate: date)?.mood, .great)

        // Update notes
        sut.updateNotes(forDate: date, notes: "Lifecycle test")
        XCTAssertEqual(sut.getEntry(byDate: date)?.notes, "Lifecycle test")

        // Delete
        sut.deleteAllEntries(forDate: date)
        XCTAssertNil(sut.getEntry(byDate: date))
    }

    func test_streak_throughLifecycle() {
        let today = Calendar.current.startOfDay(for: Date())
        let yesterday = Calendar.current.date(byAdding: .day, value: -1, to: today)!

        // Add today → streak=1
        sut.add(mood: .good, forDate: today, entryType: .listView)
        XCTAssertEqual(sut.calculateStreak(from: today).streak, 1)

        // Add yesterday → streak=2
        sut.add(mood: .great, forDate: yesterday, entryType: .listView)
        XCTAssertEqual(sut.calculateStreak(from: today).streak, 2)

        // Update today's mood → streak still 2
        sut.update(entryDate: today, withMood: .average)
        XCTAssertEqual(sut.calculateStreak(from: today).streak, 2)

        // Delete today → streak=1 (counting from yesterday)
        sut.deleteAllEntries(forDate: today)
        XCTAssertEqual(sut.calculateStreak(from: today).streak, 1)
    }

    func test_voteStatus_throughLifecycle() {
        let onboarding = OnboardingData()
        onboarding.inputDay = .Today
        // Set unlock time to 00:01 so we're always "after" unlock
        var components = Calendar.current.dateComponents([.year, .month, .day], from: Date())
        components.hour = 0
        components.minute = 1
        onboarding.date = Calendar.current.date(from: components)!

        let votingDate = ShowBasedOnVoteLogics.getCurrentVotingDate(onboardingData: onboarding)

        // Helper: check vote status using testable DataController
        func isVoteNeeded() -> Bool {
            let entry = sut.getEntry(byDate: votingDate.startOfDay)
            return entry == nil || entry?.mood == .missing
        }

        // No entry → vote needed
        XCTAssertTrue(isVoteNeeded())

        // Add entry → no vote needed
        sut.add(mood: .great, forDate: votingDate, entryType: .listView)
        XCTAssertFalse(isVoteNeeded())

        // Delete entry → vote needed again
        sut.deleteAllEntries(forDate: votingDate)
        XCTAssertTrue(isVoteNeeded())
    }

    func test_duplicateRemoval() {
        let date = makeDate(2024, 6, 15)

        // Manually insert 3 entries for same date (simulating CloudKit conflict)
        let entry1 = MoodEntryModel(forDate: date, mood: .great, entryType: .listView)
        entry1.timestamp = makeDate(2024, 6, 15, hour: 10)
        sut.modelContext.insert(entry1)

        let entry2 = MoodEntryModel(forDate: date, mood: .good, entryType: .listView)
        entry2.timestamp = makeDate(2024, 6, 15, hour: 8)
        sut.modelContext.insert(entry2)

        let entry3 = MoodEntryModel(forDate: date, mood: .missing, entryType: .filledInMissing)
        entry3.timestamp = makeDate(2024, 6, 15, hour: 12)
        sut.modelContext.insert(entry3)

        sut.save()

        let removed = sut.removeDuplicates()
        XCTAssertEqual(removed, 2)
        XCTAssertEqual(sut.getAllEntries(byDate: date).count, 1)
    }

    func test_dataListeners_fireOnMutation() {
        var listenerCallCount = 0
        sut.addNewDataListener {
            listenerCallCount += 1
        }

        // add() calls saveAndRunDataListeners internally
        sut.add(mood: .good, forDate: makeDate(2024, 6, 15), entryType: .listView)

        // add() does: delete-save (if existing) + insert + saveAndRunDataListeners
        // For a fresh add with no existing entry, listener fires once from saveAndRunDataListeners
        XCTAssertGreaterThanOrEqual(listenerCallCount, 1, "Listener should fire at least once on mutation")
    }
}
