// LoopFollow
// StatsDataService.swift

import Foundation

class StatsDataService {
    /// The injected reference can be nil when the stats UI is built before
    /// MainViewController.bootstrap() has run (cold launch with Statistics as
    /// the selected tab), so resolve lazily and fall back to the shared engine.
    private weak var injectedMainViewController: MainViewController?
    var mainViewController: MainViewController? {
        injectedMainViewController ?? MainViewController.shared
    }

    var daysToAnalyze: Int = 14 // Keep for backward compatibility
    var startDate: Date = dateTimeUtils.displayCalendar().date(byAdding: .day, value: -14, to: Date()) ?? Date()
    var endDate: Date = .init()

    private let dataFetcher: StatsDataFetcher

    /// Stores raw temp basal entries with rate and duration
    var tempBasalEntries: [TempBasalEntry] = []

    /// Structure to hold temp basal data for calculations
    struct TempBasalEntry {
        let rate: Double // U/hr (absolute rate)
        let startTime: TimeInterval // Unix timestamp
        let durationMinutes: Double // Duration in minutes
    }

    init(mainViewController: MainViewController?) {
        injectedMainViewController = mainViewController
        dataFetcher = StatsDataFetcher(mainViewController: mainViewController)
        dataFetcher.dataService = self
    }

    /// Update the date range for analysis
    func updateDateRange(start: Date, end: Date) {
        startDate = start
        endDate = end
        let calendar = dateTimeUtils.displayCalendar()
        let startDay = calendar.startOfDay(for: start)
        let endDay = calendar.startOfDay(for: end)
        let daysBetween = calendar.dateComponents([.day], from: startDay, to: endDay).day ?? 13
        daysToAnalyze = daysBetween + 1
    }

    func ensureDataAvailable(onProgress: @escaping () -> Void, completion: @escaping () -> Void) {
        guard let mainVC = mainViewController else {
            completion()
            return
        }

        let cutoffTime = startDate.timeIntervalSince1970
        let endTime = endDate.timeIntervalSince1970

        let oldestBG = mainVC.statsBGData.filter { $0.date >= cutoffTime && $0.date <= endTime }.min(by: { $0.date < $1.date })?.date
        let oldestBolus = mainVC.statsBolusData.filter { $0.date >= cutoffTime && $0.date <= endTime }.min(by: { $0.date < $1.date })?.date
        let oldestCarb = mainVC.statsCarbData.filter { $0.date >= cutoffTime && $0.date <= endTime }.min(by: { $0.date < $1.date })?.date
        let oldestBasal = mainVC.statsBasalData.filter { $0.date >= cutoffTime && $0.date <= endTime }.min(by: { $0.date < $1.date })?.date

        let bgDataCount = mainVC.statsBGData.filter { $0.date >= cutoffTime && $0.date <= endTime }.count
        let bolusDataCount = mainVC.statsBolusData.filter { $0.date >= cutoffTime && $0.date <= endTime }.count
        let carbDataCount = mainVC.statsCarbData.filter { $0.date >= cutoffTime && $0.date <= endTime }.count
        let basalDataCount = mainVC.statsBasalData.filter { $0.date >= cutoffTime && $0.date <= endTime }.count

        let minExpectedBGEntries = max(daysToAnalyze * 6, 12)
        let hasEnoughBGData = bgDataCount >= minExpectedBGEntries && (oldestBG ?? endTime) <= cutoffTime + (24 * 60 * 60)
        let minExpectedTreatmentEntries = max(daysToAnalyze, 1)
        let hasEnoughTreatmentData = (bolusDataCount + carbDataCount + basalDataCount) >= minExpectedTreatmentEntries &&
            (oldestBolus ?? endTime) <= cutoffTime + (24 * 60 * 60) &&
            (oldestCarb ?? endTime) <= cutoffTime + (24 * 60 * 60) &&
            (oldestBasal ?? endTime) <= cutoffTime + (24 * 60 * 60)

        if !hasEnoughBGData {
            dataFetcher.fetchBGData(days: daysToAnalyze) {
                DispatchQueue.main.async {
                    onProgress()
                }

                if !hasEnoughTreatmentData {
                    self.dataFetcher.fetchTreatmentsData(days: self.daysToAnalyze) {
                        DispatchQueue.main.async {
                            onProgress()
                            completion()
                        }
                    }
                } else {
                    completion()
                }
            }
        } else if !hasEnoughTreatmentData {
            dataFetcher.fetchTreatmentsData(days: daysToAnalyze) {
                DispatchQueue.main.async {
                    onProgress()
                    completion()
                }
            }
        } else {
            completion()
        }
    }

    func getBGData() -> [ShareGlucoseData] {
        guard let mainVC = mainViewController else { return [] }
        let startTime = startDate.timeIntervalSince1970
        let endTime = endDate.timeIntervalSince1970
        return mainVC.statsBGData.filter { $0.date >= startTime && $0.date <= endTime }
    }

    func getBolusData() -> [MainViewController.bolusGraphStruct] {
        guard let mainVC = mainViewController else { return [] }
        let startTime = startDate.timeIntervalSince1970
        let endTime = endDate.timeIntervalSince1970
        return mainVC.statsBolusData.filter { $0.date >= startTime && $0.date <= endTime }
    }

    func getSMBData() -> [MainViewController.bolusGraphStruct] {
        guard let mainVC = mainViewController else { return [] }
        let startTime = startDate.timeIntervalSince1970
        let endTime = endDate.timeIntervalSince1970
        return mainVC.statsSMBData.filter { $0.date >= startTime && $0.date <= endTime }
    }

    func getCarbData() -> [MainViewController.carbGraphStruct] {
        guard let mainVC = mainViewController else { return [] }
        let startTime = startDate.timeIntervalSince1970
        let endTime = endDate.timeIntervalSince1970
        return mainVC.statsCarbData.filter { $0.date >= startTime && $0.date <= endTime }
    }

    func getBasalData() -> [MainViewController.basalGraphStruct] {
        guard let mainVC = mainViewController else { return [] }
        let startTime = startDate.timeIntervalSince1970
        let endTime = endDate.timeIntervalSince1970
        return mainVC.statsBasalData.filter { $0.date >= startTime && $0.date <= endTime }
    }

    func getBasalProfile() -> [MainViewController.basalProfileStruct] {
        guard let mainVC = mainViewController else { return [] }
        return mainVC.basalProfile
    }

    func getTempBasalData() -> [TempBasalEntry] {
        let startTime = startDate.timeIntervalSince1970
        let endTime = endDate.timeIntervalSince1970
        return tempBasalEntries.filter { $0.startTime >= startTime && $0.startTime <= endTime }
    }

    /// Calculate data availability for the current date range
    func getDataAvailability() -> DataAvailabilityInfo {
        let bgData = getBGData()
        return DataAvailabilityCalculator.calculateAvailability(
            bgData: bgData,
            startDate: startDate,
            endDate: endDate
        )
    }
}
