//
//  EditFilterView.swift
//  Tusker
//
//  Created by Shadowfacts on 12/2/22.
//  Copyright © 2022 Shadowfacts. All rights reserved.
//

import SwiftUI
import Pachyderm
import TuskerComponents

struct EditFilterView: View {
    private static let expiresInOptions: [MenuPicker<TimeInterval>.Option] = {
        let f = DateComponentsFormatter()
        f.maximumUnitCount = 1
        f.unitsStyle = .full
        f.allowedUnits = [.weekOfMonth, .day, .hour, .minute]
        
        let durations: [TimeInterval] = [
                     30 * 60,
                     60 * 60,
                 6 * 60 * 60,
                24 * 60 * 60,
            3 * 24 * 60 * 60,
            7 * 24 * 60 * 60,
        ]
        return durations.map { .init(value: $0, title: f.string(from: $0)!) }
    }()
    
    @ObservedObject private var filter: EditedFilter
    private let create: Bool
    private let originallyExpired: Bool
    @EnvironmentObject private var mastodonController: MastodonController
    @Environment(\.dismiss) private var dismiss
    @State private var expiresIn: TimeInterval
    @State private var originalFilter: EditedFilter
    @State private var edited = false
    @State private var isSaving = false
    @State private var saveError: (any Error)?
    
    init(filter: EditedFilter, create: Bool, originallyExpired: Bool) {
        self.filter = filter
        self.create = create
        self.originallyExpired = originallyExpired
        self._originalFilter = State(wrappedValue: EditedFilter(copying: filter))
        if let expiresIn = filter.expiresIn {
            self._expiresIn = State(wrappedValue: Self.expiresInOptions.min(by: { a, b in
                let aDist = abs(a.value - expiresIn)
                let bDist = abs(b.value - expiresIn)
                return aDist < bDist
            })!.value)
        } else {
            self._expiresIn = State(wrappedValue: EditedFilter.defaultExpiresInForExpired)
        }
    }
    
    private var expires: Binding<Bool> {
        Binding {
            filter.expiresIn != nil
        } set: { newValue in
            filter.expiresIn = newValue ? expiresIn : nil
        }
    }
    
    var body: some View {
        Form {
            if mastodonController.instanceFeatures.filtersV2 {
                Section {
                    TextField("Title", text: Binding(get: {
                        filter.title ?? ""
                    }, set: { newValue in
                        filter.title = newValue
                    }))
                }
                .appGroupedListRowBackground()
            }
            
            Section {
                ForEach(Array($filter.keywords.enumerated()), id: \.offset) { keyword in
                    VStack {
                        TextField("Phrase", text: keyword.element.keyword)
                        Toggle("Whole Word", isOn: keyword.element.wholeWord)
                    }
                }
                .onDelete(perform: mastodonController.instanceFeatures.filtersV2 ? { indices in
                    filter.keywords.remove(atOffsets: indices)
                } : nil)
                
                if mastodonController.instanceFeatures.filtersV2 {
                    Button {
                        let new = EditedFilter.Keyword(id: nil, keyword: "", wholeWord: true)
                        withAnimation {
                            filter.keywords.append(new)
                        }
                    } label: {
                        Label("Add Keyword", systemImage: "plus")
                    }
                }
            }
            .appGroupedListRowBackground()
            
            Section {
                if mastodonController.instanceFeatures.filtersV2 {
                    Picker(selection: $filter.action) {
                        ForEach(FilterV2.Action.allCases, id: \.self) { action in
                            Text(action.displayName).tag(action)
                        }
                    } label: {
                        Text("Action")
                    }
                }

                Toggle("Expires", isOn: expires)
                
                if expires.wrappedValue {
                    Picker(selection: $expiresIn) {
                        ForEach(Self.expiresInOptions, id: \.value) { option in
                            Text(option.title).tag(option.value)
                        }
                    } label: {
                        Text("Duration")
                    }
                }
            }
            .appGroupedListRowBackground()
            
            Section {
                ForEach(FilterV1.Context.allCases, id: \.rawValue) { context in
                    Toggle(isOn: Binding(get: {
                        filter.contexts.contains(context)
                    }, set: { newValue in
                        if newValue {
                            if !filter.contexts.contains(context) {
                                filter.contexts.append(context)
                            }
                        } else if filter.contexts.count > 1 {
                            filter.contexts.removeAll(where: { $0 == context })
                        }
                    })) {
                        Text(context.displayName)
                    }
                    .toggleStyle(FilterContextToggleStyle())
                }
            } header: {
                Text("Contexts")
            }
            .appGroupedListRowBackground()
        }
        .appGroupedListBackground(container: UIHostingController<CustomizeTimelinesList>.self)
        .scrollDismissesKeyboardInteractivelyIfAvailable()
        .navigationTitle(create ? "Add Filter" : "Edit Filter")
        .navigationBarTitleDisplayMode(.inline)
        .toolbar {
            ToolbarItem(placement: .confirmationAction) {
                if isSaving {
                    ProgressView()
                        .progressViewStyle(.circular)
                } else {
                    Button("Save") {
                        saveFilter()
                    }
                    .disabled(!filter.isValid(for: mastodonController) || (!edited && originallyExpired))
                }
            }
        }
        .alertWithData("Error Saving Filter", data: $saveError, actions: { _ in
            Button("OK") {}
        }, message: { error in
            Text(error.localizedDescription)
        })
        .onChange(of: expiresIn, perform: { newValue in
            edited = true
            if expires.wrappedValue {
                filter.expiresIn = newValue
            }
        })
        .onReceive(filter.objectWillChange, perform: { _ in
            edited = true
        })
    }
    
    private func saveFilter() {
        Task {
            do {
                isSaving = true
                if create {
                    try await CreateFilterService(filter: filter, mastodonController: mastodonController).run()
                } else {
                    try await UpdateFilterService(filter: filter, mastodonController: mastodonController).run()
                }
                dismiss()
            } catch {
                isSaving = false
                saveError = error
            }
        }
    }
}

private struct FilterContextToggleStyle: ToggleStyle {
    func makeBody(configuration: Configuration) -> some View {
        Button {
            configuration.isOn.toggle()
        } label: {
            HStack {
                configuration.label
                    .foregroundColor(.primary)
                Spacer()
                if configuration.isOn {
                    Image(systemName: "checkmark")
                }
            }
        }
    }
}

private extension View {
    @available(iOS, obsoleted: 16.0)
    @ViewBuilder
    func scrollDismissesKeyboardInteractivelyIfAvailable() -> some View {
        if #available(iOS 16.0, *) {
            self.scrollDismissesKeyboard(.interactively)
        } else {
            self
        }
    }
}

//struct EditFilterView_Previews: PreviewProvider {
//    static var previews: some View {
//        EditFilterView()
//    }
//}
