//
//  FilterView.swift
//  Feels
//
//  Created by Trey Tartt on 1/12/22.
//

import SwiftUI
import CoreData

struct FilterView: View {
    let weekdays = [("Sun", 1), ("mon", 2), ("tue", 3), ("wed", 4), ("thur", 5), ("fri", 6), ("sat", 7)]
    let months = [(0, "J"), (1, "F"), (2,"M"), (3,"A"), (4,"M"), (5, "J"), (6,"J"), (7,"A"), (8,"S"), (9,"O"), (10, "N"), (11,"D")]
    
    @State private var toggle = true
    @State private var showFilter = false
    
    @FetchRequest(
        sortDescriptors: [NSSortDescriptor(keyPath: \MoodEntry.forDate, ascending: false)],
        animation: .spring())
    private var items: FetchedResults<MoodEntry>
    
    @AppStorage(UserDefaultsStore.Keys.theme.rawValue, store: GroupUserDefaults.groupDefaults) private var theme: Theme = .system
    
    @StateObject private var viewModel = FilterViewModel()
    //[
    //  2001: [0: [], 1: [], 2: []],
    //  2002: [0: [], 1: [], 2: []]
    // ]
    let columns = [
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
        GridItem(.flexible(minimum: 5, maximum: 50)),
    ]
    
    var body: some View {
        VStack {
            filterButon
                .padding([.leading, .trailing, .top])
            
            statsView
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 90, maxHeight: 90)
                .cornerRadius(10)
                .padding()
            
            Text(String(localized: "filter_view_total") + ":  \(self.viewModel.numberOfRatings)")
                .font(.title2)
            
            if showFilter {
                filterView
            }
            
            gridView
                .onAppear(perform: {
                    self.viewModel.filterEntries(startDate: Date(timeIntervalSince1970: 0), endDate: Date())
                })
        }
        .background(
            theme.bg
                .edgesIgnoringSafeArea(.all)
        )
    }
    
    private var filterButon: some View {
       Button(action: {
            withAnimation{
                showFilter.toggle()
            }
        }, label: {
            Text(showFilter ? String(localized: "filter_view_hide_filters") : String(localized: "filter_view_show_filters"))
                .frame(maxWidth: .infinity)
                .frame(height: 44)
                .foregroundColor(Color(UIColor.label))
                .background(Color(theme.secondaryBGColor))
                .cornerRadius(10)
        }).frame(maxWidth: .infinity)
    }
    
    struct StatsSubView: View {
        let data: [MoodEntry]
        let mood: Mood
        
        var body: some View {
            VStack {
                Text(String(Stats.getCountFor(moodType: mood,
                                              inData: data)))
                    .font(.title)
                Text(mood.strValue)
                    .foregroundColor(mood.color)
            }
        }
    }
    
    private var statsView: some View {
        ZStack {
            Color(theme.secondaryBGColor)
            
            HStack {
                Spacer()
                ForEach(Mood.allValues, id: \.self) { mood in
                    StatsSubView(data: self.viewModel.uncategorizedData, mood: mood)
                    Spacer()
                }
            }
        }
        .cornerRadius(10)
    }
    
    private var filterView: some View {
        VStack {
            VStack {
                ZStack {
                    Color(theme.secondaryBGColor)
                    DatePicker(
                        String(localized: "filter_view_begin_date"),
                        selection: $viewModel.entryStartDate,
                        displayedComponents: [.date]
                    ).onChange(of: viewModel.entryStartDate, perform: { value in
                        viewModel.filterEntries(startDate: viewModel.entryStartDate, endDate: viewModel.entryEndDate)
                    })
                        .padding()
                }
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44)
                .cornerRadius(10)
                .padding([.leading, .trailing])
                
                ZStack {
                    Color(theme.secondaryBGColor)
                    DatePicker(
                        String(localized: "filter_view_end_date"),
                        selection: $viewModel.entryEndDate,
                        displayedComponents: [.date]
                    ).onChange(of: viewModel.entryStartDate, perform: { value in
                        viewModel.filterEntries(startDate: viewModel.entryStartDate, endDate: viewModel.entryEndDate)
                    })
                        .padding()
                }
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44)
                .cornerRadius(10)
                .padding([.leading, .trailing])
                
                ZStack {
                    Color(theme.secondaryBGColor)
                    HStack {
                        Spacer()
                        ForEach(weekdays.indices, id: \.self) { dayIdx in
                            let day = String(weekdays[dayIdx].0)
                            let value = weekdays[dayIdx].1
                            
                            Button(day.capitalized, action: {
                                if let index = viewModel.selectedDays.firstIndex(of: value) {
                                    viewModel.selectedDays.remove(at: index)
                                } else {
                                    viewModel.selectedDays.append(value)
                                }
                                viewModel.filterEntries(startDate: viewModel.entryStartDate,
                                                        endDate: viewModel.entryEndDate)
                            })
                                .frame(maxWidth: .infinity)
                                .foregroundColor(viewModel.selectedDays.contains(value) || viewModel.selectedDays.isEmpty ? .green : .red)
                        }
                        Spacer()
                    }
                }
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 44, maxHeight: 44)
                .cornerRadius(10)
                .padding([ .leading, .trailing])
            }
            filterButon
                .padding([.leading, .trailing, .top])
        }
    }
    
    private var monthsHeader: some View {
        LazyVGrid(columns: columns, spacing: 0) {
            ForEach(months, id: \.self.0) { item in
                Text(item.1)
                    .textCase(.uppercase)
            }
        }.padding([.leading, .trailing, .top])
    }
    
    private var gridView: some View {
        VStack {
            monthsHeader
                .cornerRadius(10)
                .padding([.leading, .trailing])
            
            VStack {
                ScrollView {
                    ForEach(Array(self.viewModel.data.keys.sorted(by: >)), id: \.self) { yearKey in
                        let yearData = self.viewModel.data[yearKey]!
                        Text(String(yearKey))
                            .font(.title)
                        yearGridView(yearData: yearData, columns: columns)
                            .background(
                                Color(theme.secondaryBGColor)
                            )
                            .cornerRadius(10)
                    }
                }
                .simultaneousGesture(DragGesture().onChanged({ _ in
                    withAnimation{
                        showFilter = false
                    }
                }))
                .padding()
            }
        }
    }
    
    private struct yearGridView: View {
        let yearData: [Int: [DayChartView]]
        let columns: [GridItem]
        
        var body: some View {
            VStack {
                LazyVGrid(columns: columns, spacing: 0) {
                    ForEach(Array(yearData.keys.sorted(by: <)), id: \.self) { monthKey in
                        let monthData = yearData[monthKey]!
                        VStack {
                            monthGridView(monthData: monthData)
                        }
                    }
                }
                .padding([.leading, .trailing, .top, .bottom])
            }
            .cornerRadius(10)
        }
    }
    
    private struct monthGridView: View {
        let monthData: [DayChartView]
        
        var body: some View {
            VStack {
                ForEach(monthData, id: \.self) { view in
                    view
                }
            }
        }
    }
}

struct FilterView_Previews: PreviewProvider {
    static var previews: some View {
        Group {
            FilterView()
            
            FilterView()
                .preferredColorScheme(.dark)
        }
    }
}
