//
//  OppositeCollapseKeywordsView.swift
//  Tusker
//
//  Created by Shadowfacts on 11/1/20.
//  Copyright © 2020 Shadowfacts. All rights reserved.
//

import SwiftUI

struct OppositeCollapseKeywordsView: View {
    @ObservedObject private var preferences = Preferences.shared
    // Can't use the raw [String] for keywords, because we need a fixed ID (within the lifetime of this view) for ForEach
    @State private var keywords: [Keyword] = Preferences.shared.oppositeCollapseKeywords.map(Keyword.init) {
        didSet {
            preferences.oppositeCollapseKeywords = keywords.map(\.value)
        }
    }
    @State private var valueToAdd = ""
    @State private var makeAddFieldFirstResponder = false
    
    var body: some View {
        ZStack {
            // the background from the grouped ListStyle clips to the safe area, so when the keyboard is hiding/showing
            // the color behind it can be seen, which looks odd
//            Color(UIColor.secondarySystemBackground)
//                .edgesIgnoringSafeArea(.bottom)
            
            List {
                Section(footer: Text("A post matches if its content warning contains the text of a keyword, ignoring case.")) {
                    ForEach(keywords) { (keyword) in
                        Row(keyword: keyword) {
                            keywords.removeAll(where: { $0.id == keyword.id })
                        }
                    }
                    .onDelete(perform: self.removeKeywords)
                    
                    FocusableTextField(placeholder: "Add Keyword", text: $valueToAdd, becomeFirstResponder: $makeAddFieldFirstResponder, onCommit: self.addKeyword)
                }
                .appGroupedListRowBackground()
            }
            .animation(.default, value: keywords.map(\.id))
            .listStyle(.grouped)
            .appGroupedListBackground(container: PreferencesNavigationController.self)
        }
        .onAppear(perform: updateAppearance)
        .navigationBarTitle(preferences.expandAllContentWarnings ? "Collapse Post CW Keywords" : "Expand Post CW Keywords")
    }
    
    private func updateAppearance() {
        if #available(iOS 16.0, *) {
            // no longer necessary
        } else {
            UIScrollView.appearance(whenContainedInInstancesOf: [PreferencesNavigationController.self]).keyboardDismissMode = .interactive
        }
    }
    
    private func commitExisting(at index: Int) -> () -> Void {
        return {
            if keywords[index].value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                keywords.remove(at: index)
            }
            
            makeAddFieldFirstResponder = true
        }
    }
    
    private func removeKeywords(_ indices: IndexSet) {
        keywords.remove(atOffsets: indices)
    }
    
    private func addKeyword() {
        guard !valueToAdd.isEmpty else { return }
        keywords.append(Keyword(valueToAdd))
        valueToAdd = ""
    }
}

fileprivate extension OppositeCollapseKeywordsView {
    // Class for wrapping keywords that provides a fixed id SwiftUI's ForEach can use
    class Keyword: ObservableObject, Identifiable {
        let id = UUID()
        @Published var value: String
        
        init(_ value: String) {
            self.value = value
        }
    }
}

fileprivate extension OppositeCollapseKeywordsView {
    // Use a separate View for the row so it can use @ObservableObject to get a binding for the keyword's value
    struct Row: View {
        @ObservedObject var keyword: Keyword
        let removeKeyword: () -> Void
        
        var body: some View {
            FocusableTextField(placeholder: "Keyword", text: $keyword.value) {
                if keyword.value.trimmingCharacters(in: .whitespacesAndNewlines).isEmpty {
                    removeKeyword()
                }
            }
        }
    }
}

struct OppositeCollapseKeywordsView_Previews: PreviewProvider {
    static var previews: some View {
        OppositeCollapseKeywordsView()
    }
}
