//
//  StatsView.swift
//  LeCountdown
//
//  Created by Laurent Morvillier on 17/02/2023.
//

import SwiftUI
import CoreData
import Charts

class StatModel: ObservableObject {
    
    @Published var statValues: [StatValue] = []
    
    @Published var isComputing = false
    
    @Published var error: Error? = nil
    
    func compute(activity: Activity, filter: Filter?) {
        
        self.isComputing = true
        
        PersistenceController.shared.container.performBackgroundTask { context in
            
            var values: [StatValue] = []
            
            do {
                values = try context.compute(activity: activity, stats: Stat.allCases, filter: filter)
            } catch {
                Logger.error(error)
                self.error = error
            }
            
            DispatchQueue.main.async {
                self.statValues = values
                self.isComputing = false
            }
        }
    }
    
}

struct GraphsView: View {
    
    var activity: Activity
    var timeFrame: TimeFrame
    var filter: Filter? = nil
    
    @StateObject var model: StatModel = StatModel()
    
    var body: some View {
        
        Section {
            VStack() {
                
                if self.model.isComputing {
                    ProgressView()
                        .progressViewStyle(CircularProgressViewStyle())
                } else {
                    VStack(alignment: .leading) {
                        ForEach(self.model.statValues) { statValue in
                            GraphView(statValue: statValue, timeFrame: self.timeFrame)
                            //                        .padding(.vertical)
                        }
                    }
                }
            }
        }
        .onAppear() {
            self.model.compute(activity: self.activity, filter: self.filter)
        }
        .navigationTitle(self.activity.name ?? "")
    }
    
}

struct StatView: View {
    
    var statValue: StatValue
    
    var body: some View {
        VStack(alignment: .leading) {
            Text(self.statValue.stat.localizedName.uppercased())
                .font(.footnote)
            Text(self.statValue.formattedValue)
                .font(.system(.title, weight: .bold))
        }
    }
    
}

struct GraphView: View {
    
    var statValue: StatValue
    var timeFrame: TimeFrame
    
    var body: some View {
        VStack(alignment: .leading) {
            
            StatView(statValue: self.statValue)
//            HStack {
//                Text(self.statValue.stat.localizedName.uppercased())
//                Text(self.statValue.formattedValue)
//            }
            Chart(self.statValue.chartPoint(timeFrame: self.timeFrame)) { point in
                
                let stat: Stat = self.statValue.stat
                
                switch stat {
                case .count, .totalDuration:
                    BarMark(x: .value("date", point.index),
                            y: .value("value", point.value.doubleValue))
                default:
                    LineMark(x: .value("date", point.index),
                             y: .value("value", point.value.doubleValue))
                }
            }.chartXAxis(.hidden)
            .chartYAxis {
                AxisMarks() { value in
                    AxisValueLabel {
                        Text(self.statValue.stat.format(axisValue: value))
                    }
                }
            }.frame(height: 200.0)
        }
    }
    
}

fileprivate extension Stat {
    
    func format(axisValue: AxisValue) -> String {
        let text: String?
        switch self {
        case .count:
            text = axisValue.as(Int.self)?.formatted()
        case .totalDuration, .averageDuration:
            text = axisValue.as(Double.self)?.hourMinuteSecond
        }
        return text ?? NSLocalizedString("Formatting failed", comment: "")
    }
    
}

struct StatGraphView_Previews: PreviewProvider {
    
    static let points: [Point] = [Point(date: Date(), value: 1),
                                  Point(date: Date(), value: 1),
                                  Point(date: Date(timeIntervalSince1970: 100000), value: 1)]
    
    static var previews: some View {
        GraphView(statValue: StatValue(stat: .count, value: NSDecimalNumber(integerLiteral: 3), points: points), timeFrame: .all)
    }
}

struct StatView_Previews: PreviewProvider {
    static var previews: some View {
        StatView(statValue: StatValue(stat: .count, value: NSDecimalNumber(integerLiteral: 3)))
    }
}

struct StatsView_Previews: PreviewProvider {
    static var previews: some View {
        GraphsView(activity: Activity.fake(context: PersistenceController.preview.container.viewContext),
                  timeFrame: .all)
    }
}
