import SwiftUI

struct MultiFileSelectionView: View {

    @Environment(\.dismiss)
    private var dismiss

    @EnvironmentObject
    private var content: Content

    @Binding
    private var selectedFiles: [FileResource]

    let allowedType: FileTypeCategory?

    let insertSorted: Bool

    @State
    private var selectedFileType: FileTypeCategory?

    @State
    private var searchString = ""

    @State
    private var newSelection: [FileResource]

    init(selectedFiles: Binding<[FileResource]>, allowedType: FileTypeCategory? = nil, insertSorted: Bool = false) {
        self._selectedFiles = selectedFiles
        self.newSelection = selectedFiles.wrappedValue
        self.allowedType = allowedType
        self.selectedFileType = allowedType ?? .image
        self.insertSorted = insertSorted
    }

    private var filesBySelectedType: [FileResource] {
        guard let selectedFileType else {
            return content.files
        }
        return content.files.filter { selectedFileType == $0.type.category }
    }

    private var filteredFiles: [FileResource] {
        guard !searchString.isEmpty else {
            return filesBySelectedType
        }
        return filesBySelectedType.filter { $0.identifier.contains(searchString) }
    }

    var body: some View {
        GeometryReader { geo in
            HStack {
                VStack {
                    Text("Selected files")
                        .font(.title)
                    List {
                        ForEach(newSelection) { file in
                            HStack {
                                Image(systemSymbol: .minusCircleFill)
                                    .foregroundStyle(.red)
                                    .contentShape(Rectangle())
                                    .onTapGesture { deselect(file: file) }
                                Text(file.identifier)
                                Spacer()
                            }
                        }
                        .onMove(perform: moveSelectedFile)
                    }
                    HStack {
                        Button("Cancel") {
                            DispatchQueue.main.async {
                                dismiss()
                            }
                        }
                        Button("Save") {
                            selectedFiles = newSelection
                            dismiss()
                        }
                    }
                }.frame(width: geo.size.width / 2)
                VStack {
                    Picker("", selection: $selectedFileType) {
                        let all: FileTypeCategory? = nil
                        Text("All").tag(all)
                        ForEach(FileTypeCategory.allCases) { type in
                            Text(type.text).tag(type)
                        }
                    }
                    .padding(.trailing, 7)
                    .disabled(allowedType != nil)
                    TextField("", text: $searchString, prompt: Text("Search"))
                        .textFieldStyle(.roundedBorder)
                        .padding(.horizontal, 8)
                    List(filteredFiles) { file in
                        HStack {
                            if newSelection.contains(file) {
                                Image(systemSymbol: .checkmarkCircleFill)
                                    .foregroundStyle(.gray)
                            } else {
                                Image(systemSymbol: .plusCircleFill)
                                    .foregroundStyle(.green)
                            }
                            Text(file.identifier)
                            Spacer()
                        }
                        .contentShape(Rectangle())
                        .onTapGesture { select(file: file) }
                    }
                }.frame(width: geo.size.width / 2)
            }
            .frame(minHeight: 500, idealHeight: 600)
        }
        .frame(minHeight: 500, idealHeight: 600)
        .padding()

    }

    private func deselect(file: FileResource) {
        guard let index = newSelection.firstIndex(of: file) else {
            return
        }
        newSelection.remove(at: index)
    }

    private func select(file: FileResource) {
        guard !newSelection.contains(file) else {
            return
        }
        guard insertSorted else {
            newSelection.append(file)
            return
        }
        newSelection.insertSorted(file)
    }

    private func moveSelectedFile(from source: IndexSet, to destination: Int) {
        newSelection.move(fromOffsets: source, toOffset: destination)
    }
}
