//
//  FeelsWidget.swift
//  FeelsWidget
//
//  Created by Trey Tartt on 1/7/22.
//

import WidgetKit
import SwiftUI
import Intents
import CoreData

class WatchTimelineView: Identifiable {
    let id = UUID()
    let image: Image
    let graphic: Image
    let date: Date
    let color: Color
    
    init(image: Image, date: Date, color: Color, graphic: Image) {
        self.image = image
        self.date = date
        self.color =  color
        self.graphic = graphic
    }
}

struct TimeLineCreator {
    static func createViews(daysBack: Int) -> [WatchTimelineView] {
        var timeLineView = [WatchTimelineView]()
        var startDayOffset = 0
        
        if !UserDefaultsStore.getOnboarding().ableToVoteBasedOnCurentTime() {
            startDayOffset = 1
        }
        
        for day in startDayOffset..<daysBack{
            let day = Calendar.current.date(byAdding: .day, value: -day, to: Date())!
            
            let dayStart = Calendar.current.startOfDay(for: day)
            let dayEnd = Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: dayStart)!
            
            if let todayEntry = PersistenceController.shared.getData(startDate: dayStart, endDate: dayEnd, includedDays: []).first {
                timeLineView.append(WatchTimelineView(image: todayEntry.mood.icon,
                                                  date: dayStart,
                                                  color: todayEntry.mood.color,
                                                  graphic: todayEntry.mood.graphic))
            } else {
                timeLineView.append(WatchTimelineView(image: Mood.missing.icon,
                                                  date: dayStart,
                                                  color: Mood.missing.color,
                                                  graphic: Mood.missing.graphic))
            }
        }
        timeLineView = timeLineView.sorted(by: { $0.date > $1.date  })
        return timeLineView
    }
}

struct Provider: IntentTimelineProvider {
    let timeLineCreator = TimeLineCreator()
    
    /*
     placeholder for widget, no data
     gets redacted auto
     */
    func placeholder(in context: Context) -> SimpleEntry {
        return SimpleEntry(date: Date(),
                           configuration: ConfigurationIntent(),
                           timeLineViews: Array(TimeLineCreator.createViews(daysBack: 11).prefix(10)))
    }
    
    func getSnapshot(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (SimpleEntry) -> ()) {
        let entry = SimpleEntry(date: Date(),
                           configuration: ConfigurationIntent(),
                                timeLineViews: Array(TimeLineCreator.createViews(daysBack: 11).prefix(10)))
        completion(entry)
    }
    
    func getTimeline(for configuration: ConfigurationIntent, in context: Context, completion: @escaping (Timeline<Entry>) -> ()) {
        let entry = SimpleEntry(date: Calendar.current.date(byAdding: .second, value: 15, to: Date())!,
                                configuration: ConfigurationIntent(),
                                timeLineViews: nil)
        
        let midNightEntry = SimpleEntry(date: Calendar.current.date(bySettingHour: 23, minute: 59, second: 59, of: Date())!,
                                configuration: ConfigurationIntent(),
                                timeLineViews: nil)
        
        let date = Calendar.current.date(byAdding: .second, value: 10, to: Date())!
        let timeline = Timeline(entries: [entry, midNightEntry], policy: .after(date))
        completion(timeline)
    }
}

struct SimpleEntry: TimelineEntry {
    let date: Date
    let configuration: ConfigurationIntent
    let timeLineViews: [WatchTimelineView]?
    let showStats: Bool
    
    init(date: Date, configuration: ConfigurationIntent, timeLineViews: [WatchTimelineView]?, showStats: Bool = false) {
        self.date = date
        self.configuration = configuration
        self.timeLineViews = timeLineViews
        self.showStats = showStats
    }
}

/**********************************************************/
struct FeelsWidgetEntryView : View {
    @Environment(\.sizeCategory) var sizeCategory
    @Environment(\.widgetFamily) var family
    
    var entry: Provider.Entry
    
    @ViewBuilder
    var body: some View {
        ZStack {
            Color(UIColor.systemBackground)
            switch family {
            case .systemSmall:
                SmallWidgetView(entry: entry)
            case .systemMedium:
                MediumWidgetView(entry: entry)
            case .systemLarge:
                LargeWidgetView(entry: entry)
            case .systemExtraLarge:
                LargeWidgetView(entry: entry)
            @unknown default:
                fatalError()
            }
        }.onReceive(NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange)) { _ in
            // make sure you don't call this too often
            WidgetCenter.shared.reloadAllTimelines()
        }
    }
}

struct SmallWidgetView: View {
    var entry: Provider.Entry
    var timeLineView = [WatchTimelineView]()
    
    init(entry: Provider.Entry) {
        self.entry = entry
        timeLineView = [TimeLineCreator.createViews(daysBack: 2).first!]
    }
    
    var body: some View {
        ZStack {
            Color(UIColor.secondarySystemBackground)
            HStack {
                ForEach(self.timeLineView) { watchView in
                    EntryCard(timeLineView: watchView)
                }
            }
            .padding()
        }
        .clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
        .frame(minHeight: 0, maxHeight: 55)
        .padding()
    }
}

struct MediumWidgetView: View {
    var entry: Provider.Entry
    var timeLineView = [WatchTimelineView]()

    init(entry: Provider.Entry) {
        self.entry = entry
        timeLineView = Array(TimeLineCreator.createViews(daysBack: 6).prefix(5))
    }
    
    var body: some View {
        VStack {
            Spacer()
            
            TimeHeaderView(startDate: timeLineView.first!.date, endDate: timeLineView.last!.date)
                .frame(minWidth: 0, maxWidth: .infinity)
                .multilineTextAlignment(.leading)
            
            TimeBodyView(group: timeLineView)
                .clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
                .frame(minHeight: 0, maxHeight: 55)
                .padding()
            
            Spacer()
        }
    }
}

struct LargeWidgetView: View {
    var entry: Provider.Entry
    var timeLineView = [WatchTimelineView]()

    init(entry: Provider.Entry) {
        self.entry = entry
        timeLineView = Array(TimeLineCreator.createViews(daysBack: 11).prefix(10))
    }
    
    var firstGroup: ([WatchTimelineView], String) {
        return (Array(self.timeLineView.prefix(5)), UUID().uuidString)
    }
    
    var secondGroup: ([WatchTimelineView], String) {
        return (Array(self.timeLineView.suffix(5)), UUID().uuidString)
    }
    
    var body: some View {
        VStack {
            Spacer()
            
            ForEach([firstGroup, secondGroup], id: \.1) { group in
                VStack {
                    Spacer()
                    
                    TimeHeaderView(startDate: group.0.first!.date, endDate: group.0.last!.date)
                        .frame(minWidth: 0, maxWidth: .infinity)
                        .multilineTextAlignment(.leading)
                    
                    TimeBodyView(group: group.0)
                        .clipShape(RoundedRectangle(cornerRadius: 25, style: .continuous))
                        .frame(minHeight: 0, maxHeight: 55)
                        .padding()
                    
                    Spacer()
                }
            }
            
            Spacer()
        }
    }
}
/**********************************************************/
struct FeelsGraphicWidgetEntryView : View {
    @Environment(\.sizeCategory) var sizeCategory
    @Environment(\.widgetFamily) var family
    
    var entry: Provider.Entry
    
    @ViewBuilder
    var body: some View {
        SmallGraphicWidgetView(entry: entry)
            .onReceive(NotificationCenter.default.publisher(for: .NSPersistentStoreRemoteChange)) { _ in
            // make sure you don't call this too often
            WidgetCenter.shared.reloadAllTimelines()
        }
    }
}

struct SmallGraphicWidgetView: View {
    var entry: Provider.Entry
    var timeLineView = [WatchTimelineView]()
    
    init(entry: Provider.Entry) {
        self.entry = entry
        timeLineView = [TimeLineCreator.createViews(daysBack: 2).first!]
    }
    
    var body: some View {
        GeometryReader { geo in
            timeLineView.first!.graphic
                .resizable()
                .scaledToFit()
        }
    }
}
/**********************************************************/
struct FeelsIconWidgetEntryView : View {
    @Environment(\.sizeCategory) var sizeCategory
    @Environment(\.widgetFamily) var family
    
    var entry: Provider.Entry
    
    @ViewBuilder
    var body: some View {
        SmallIconView(entry: entry)
    }
}

struct SmallIconView: View {
    var entry: Provider.Entry

    var body: some View {
        GeometryReader { geo in
            Mood.missing.graphic
                .resizable()
                .scaledToFit()
        }
    }
}
/**********************************************************/
struct TimeHeaderView: View {
    let startDate: Date
    let endDate: Date
    
    var formatter: DateFormatter {
        let dateFormatter = DateFormatter()
        dateFormatter.dateStyle = .medium
        return dateFormatter
    }
    
    var body: some View {
        HStack {
            Text(startDate, formatter: formatter)
                .font(.system(.footnote))
            Text(" - ")
                .font(.system(.footnote))
            Text(endDate, formatter: formatter)
                .font(.system(.footnote))
        }
    }
}

struct TimeBodyView: View {
    let group: [WatchTimelineView]
    
    var body: some View {
        ZStack {
            Color(UIColor.secondarySystemBackground)
            HStack {
                ForEach(group) { watchView in
                    EntryCard(timeLineView: watchView)
                }
            }
            .padding()
        }
    }
}

struct EntryCard: View {
    var timeLineView: WatchTimelineView
    
    var body: some View {
        timeLineView.image
            .resizable()
            .aspectRatio(contentMode: .fit)
            .frame(width: 50, height: 50, alignment: .center)
            .foregroundColor(timeLineView.color)
    }
}

@main
struct FeelsBundle: WidgetBundle {
    var body: some Widget {
        FeelsWidget()
        FeelsGraphicWidget()
        FeelsIconWidget()
    }
}

struct FeelsWidget: Widget {
    let kind: String = "FeelsWidget"
    
    var body: some WidgetConfiguration {
        IntentConfiguration(kind: kind,
                            intent: ConfigurationIntent.self,
                            provider: Provider()) { entry in
            FeelsWidgetEntryView(entry: entry)
        }
                            .configurationDisplayName("Feels")
                            .description("")
                            .supportedFamilies([.systemSmall, .systemMedium, .systemLarge])
    }
}

struct FeelsIconWidget: Widget {
    let kind: String = "FeelsIconWidget"
    
    var body: some WidgetConfiguration {
        IntentConfiguration(kind: kind,
                            intent: ConfigurationIntent.self,
                            provider: Provider()) { entry in
            FeelsIconWidgetEntryView(entry: entry)
        }
                            .configurationDisplayName("Feels Icon")
                            .description("")
                            .supportedFamilies([.systemSmall])
    }
}

struct FeelsGraphicWidget: Widget {
    let kind: String = "FeelsGraphicWidget"
    
    var body: some WidgetConfiguration {
        IntentConfiguration(kind: kind,
                            intent: ConfigurationIntent.self,
                            provider: Provider()) { entry in
            FeelsGraphicWidgetEntryView(entry: entry)
        }
                            .configurationDisplayName("Mood Graphic")
                            .description("")
                            .supportedFamilies([.systemSmall])
    }
}

struct FeelsWidget_Previews: PreviewProvider {
    static var previews: some View {
        Group {
//            FeelsWidgetEntryView(entry: SimpleEntry(date: Date(),
//                                                    configuration: ConfigurationIntent(),
//                                                    timeLineViews: FeelsWidget_Previews.data))
//                .previewContext(WidgetPreviewContext(family: .systemSmall))
//                .environment(\.sizeCategory, .small)
//
//            FeelsWidgetEntryView(entry: SimpleEntry(date: Date(),
//                                                    configuration: ConfigurationIntent(),
//                                                    timeLineViews: FeelsWidget_Previews.data))
//                .previewContext(WidgetPreviewContext(family: .systemMedium))
//                .environment(\.sizeCategory, .medium)
//
//            FeelsWidgetEntryView(entry: SimpleEntry(date: Date(),
//                                                    configuration: ConfigurationIntent(),
//                                                    timeLineViews: FeelsWidget_Previews.data))
//                .previewContext(WidgetPreviewContext(family: .systemLarge))
//                .environment(\.sizeCategory, .large)
        }
    }
}
