//
//  InsightsViewModel.swift
//  Reflect
//
//  Created by Claude Code on 12/9/24.
//

import Foundation
import SwiftUI

/// Represents a single insight to display in the UI
struct Insight: Identifiable {
    let id = UUID()
    let icon: String
    let title: String
    let description: String
    let mood: Mood?
}

/// Loading state for each insight section
enum InsightLoadingState: Equatable {
    case idle
    case loading
    case loaded
    case error(String)
}

/// ViewModel for the Insights tab - uses Apple Foundation Models for AI-powered insights
@MainActor
class InsightsViewModel: ObservableObject {

    // MARK: - Published Properties

    @Published var monthInsights: [Insight] = []
    @Published var yearInsights: [Insight] = []
    @Published var allTimeInsights: [Insight] = []

    @Published var monthLoadingState: InsightLoadingState = .idle
    @Published var yearLoadingState: InsightLoadingState = .idle
    @Published var allTimeLoadingState: InsightLoadingState = .idle

    @Published var isAIAvailable: Bool = false

    // MARK: - Dependencies

    /// Stored as Any? to avoid referencing @available(iOS 26, *) type at the property level
    private var insightService: Any?
    private let healthService = HealthService.shared
    private let calendar = Calendar.current

    // MARK: - Initialization

    private var dataListenerToken: DataController.DataListenerToken?

    init() {
        if #available(iOS 26, *) {
            let service = FoundationModelsInsightService()
            insightService = service
            isAIAvailable = service.isAvailable
        } else {
            insightService = nil
            isAIAvailable = false
        }

        dataListenerToken = DataController.shared.addNewDataListener { [weak self] in
            self?.onDataChanged()
        }
    }

    deinit {
        if let token = dataListenerToken {
            Task { @MainActor in
                DataController.shared.removeDataListener(token: token)
            }
        }
    }

    /// Called when mood data changes in another tab. Invalidates cached insights
    /// so they are regenerated with fresh data on next view appearance.
    private func onDataChanged() {
        if #available(iOS 26, *), let service = insightService as? FoundationModelsInsightService {
            service.invalidateCache()
        }
        monthLoadingState = .idle
        yearLoadingState = .idle
        allTimeLoadingState = .idle
    }

    // MARK: - Public Methods

    /// Generate insights for all time periods
    func generateInsights() {
        Task {
            await generateAllInsights()
        }
    }

    /// Force refresh all insights (invalidates cache)
    func refreshInsights() {
        if #available(iOS 26, *), let service = insightService as? FoundationModelsInsightService {
            service.invalidateCache()
        }
        generateInsights()
    }

    // MARK: - Private Methods

    private func generateAllInsights() async {
        let now = Date()

        // Get date ranges
        let monthStart = calendar.date(from: calendar.dateComponents([.year, .month], from: now))!
        let yearStart = calendar.date(from: calendar.dateComponents([.year], from: now))!
        let allTimeStart = Date(timeIntervalSince1970: 0)

        // Fetch entries for each period
        let monthEntries = DataController.shared.getData(startDate: monthStart, endDate: now, includedDays: [1, 2, 3, 4, 5, 6, 7])
        let yearEntries = DataController.shared.getData(startDate: yearStart, endDate: now, includedDays: [1, 2, 3, 4, 5, 6, 7])
        let allTimeEntries = DataController.shared.getData(startDate: allTimeStart, endDate: now, includedDays: [1, 2, 3, 4, 5, 6, 7])

        // Generate insights concurrently for all three periods
        await withTaskGroup(of: Void.self) { group in
            group.addTask { @MainActor in
                await self.generatePeriodInsights(
                    entries: monthEntries,
                    periodName: "this month",
                    updateState: { self.monthLoadingState = $0 },
                    updateInsights: { self.monthInsights = $0 }
                )
            }

            group.addTask { @MainActor in
                await self.generatePeriodInsights(
                    entries: yearEntries,
                    periodName: "this year",
                    updateState: { self.yearLoadingState = $0 },
                    updateInsights: { self.yearInsights = $0 }
                )
            }

            group.addTask { @MainActor in
                await self.generatePeriodInsights(
                    entries: allTimeEntries,
                    periodName: "all time",
                    updateState: { self.allTimeLoadingState = $0 },
                    updateInsights: { self.allTimeInsights = $0 }
                )
            }
        }
    }

    private func generatePeriodInsights(
        entries: [MoodEntryModel],
        periodName: String,
        updateState: @escaping (InsightLoadingState) -> Void,
        updateInsights: @escaping ([Insight]) -> Void
    ) async {
        // Filter valid entries
        let validEntries = entries.filter { ![.missing, .placeholder].contains($0.mood) }

        // Handle empty data case
        guard !validEntries.isEmpty else {
            updateInsights([Insight(
                icon: "questionmark.circle",
                title: "No Data Yet",
                description: "Start logging your moods to see insights for \(periodName).",
                mood: nil
            )])
            updateState(.loaded)
            return
        }

        // Check if AI is available
        guard isAIAvailable else {
            updateInsights([Insight(
                icon: "brain.head.profile",
                title: "AI Unavailable",
                description: "Apple Intelligence is required for personalized insights. Please enable it in Settings.",
                mood: nil
            )])
            updateState(.error("AI not available"))
            return
        }

        updateState(.loading)

        // Fetch health data if enabled - pass raw averages to AI for correlation analysis
        var healthAverages: HealthService.HealthAverages?
        if healthService.isEnabled && healthService.isAuthorized {
            let healthData = await healthService.fetchHealthData(for: validEntries)
            healthAverages = healthService.computeHealthAverages(entries: validEntries, healthData: healthData)
        }

        if #available(iOS 26, *), let service = insightService as? FoundationModelsInsightService {
            do {
                let insights = try await service.generateInsights(
                    for: validEntries,
                    periodName: periodName,
                    count: 5,
                    healthAverages: healthAverages
                )
                updateInsights(insights)
                updateState(.loaded)
            } catch {
                // On error, provide a helpful message
                updateInsights([Insight(
                    icon: "exclamationmark.triangle",
                    title: "Insights Unavailable",
                    description: "Unable to generate AI insights right now. Please try again later.",
                    mood: nil
                )])
                updateState(.error(error.localizedDescription))
            }
        } else {
            updateInsights([Insight(
                icon: "brain.head.profile",
                title: "AI Unavailable",
                description: "Apple Intelligence is required for personalized insights. Please enable it in Settings.",
                mood: nil
            )])
            updateState(.error("AI not available"))
        }
    }
}
