import Siesta
import SwiftUI

struct PlaylistFormView: View {
    @Binding var playlist: Playlist!

    @State private var name = ""
    @State private var visibility = Playlist.Visibility.public

    @State private var valid = false
    @State private var presentingDeleteConfirmation = false

    @State private var formError = ""
    @State private var presentingErrorAlert = false

    @Environment(\.colorScheme) private var colorScheme
    @Environment(\.presentationMode) private var presentationMode

    @ObservedObject private var accounts = AccountsModel.shared
    @ObservedObject private var playlists = PlaylistsModel.shared

    var editing: Bool {
        playlist != nil
    }

    var body: some View {
        Group {
            #if os(macOS) || os(iOS)
                VStack(alignment: .leading) {
                    HStack {
                        Text(editing ? "Edit Playlist" : "Create Playlist")
                            .font(.title2.bold())

                        Spacer()

                        Button("Cancel") {
                            presentationMode.wrappedValue.dismiss()
                        }.keyboardShortcut(.cancelAction)
                    }
                    .padding(.horizontal)

                    Form {
                        TextField("Name", text: $name, onCommit: validate)
                            .frame(maxWidth: 450)
                            .padding(.leading, 10)
                            .disabled(editing && !accounts.app.userPlaylistsAreEditable)

                        if accounts.app.userPlaylistsHaveVisibility {
                            visibilityFormItem
                                .pickerStyle(.segmented)
                        }
                    }
                    #if os(macOS)
                    .padding(.horizontal)
                    #endif

                    HStack {
                        if editing {
                            deletePlaylistButton
                        }

                        Spacer()

                        Button("Save", action: submitForm)
                            .disabled(!valid || (editing && !accounts.app.userPlaylistsAreEditable))
                            .alert(isPresented: $presentingErrorAlert) {
                                Alert(
                                    title: Text("Error when accessing playlist"),
                                    message: Text(formError)
                                )
                            }
                            .keyboardShortcut(.defaultAction)
                    }
                    .frame(minHeight: 35)
                    .padding(.horizontal)
                }

                #if os(iOS)
                .padding(.vertical)
                #else
                .frame(width: 400, height: accounts.app.userPlaylistsHaveVisibility ? 150 : 120)
                #endif

            #else
                VStack {
                    Group {
                        header
                        form
                    }
                    .frame(maxWidth: 1000)
                }
                .frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity)
                .background(Color.background(scheme: colorScheme))
            #endif
        }
        .onChange(of: name) { _ in validate() }
        .onAppear(perform: initializeForm)
    }

    #if os(tvOS)
        var header: some View {
            HStack {
                Text(editing ? "Edit Playlist" : "Create Playlist")
                    .font(.title2.bold())

                Spacer()

                #if !os(tvOS)
                    Button("Cancel") {
                        dismiss()
                    }
                    .keyboardShortcut(.cancelAction)
                #endif
            }
            .padding(.horizontal)
        }

        var form: some View {
            VStack(alignment: .trailing) {
                VStack {
                    Text("Name")
                        .frame(maxWidth: .infinity, alignment: .leading)

                    TextField("Playlist Name", text: $name, onCommit: validate)
                        .disabled(editing && !accounts.app.userPlaylistsAreEditable)
                }

                if accounts.app.userPlaylistsHaveVisibility {
                    HStack {
                        Text("Visibility")
                            .frame(maxWidth: .infinity, alignment: .leading)

                        visibilityFormItem
                    }
                    .padding(.top, 10)
                }

                HStack {
                    Spacer()

                    Button("Save", action: submitForm)
                        .disabled(!valid || (editing && !accounts.app.userPlaylistsAreEditable))
                }
                .padding(.top, 40)

                if editing {
                    Divider()
                    HStack {
                        Text("Delete playlist")
                            .font(.title2.bold())
                        Spacer()
                        deletePlaylistButton
                    }
                }
            }
            .padding(.horizontal)
        }
    #endif

    func initializeForm() {
        guard editing else {
            return
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
            name = playlist.title
            visibility = playlist.visibility

            validate()
        }
    }

    func validate() {
        valid = !name.isEmpty
    }

    func submitForm() {
        guard valid else {
            return
        }

        accounts.api.playlistForm(name, visibility.rawValue, playlist: playlist, onFailure: { error in
            formError = "(\(error.httpStatusCode ?? -1)) \(error.userMessage)"
            presentingErrorAlert = true
        }) { modifiedPlaylist in
            self.playlist = modifiedPlaylist
            playlists.load(force: true)

            presentationMode.wrappedValue.dismiss()
        }
    }

    var visibilityFormItem: some View {
        #if os(macOS)
            Picker("Visibility", selection: $visibility) {
                ForEach(Playlist.Visibility.allCases) { visibility in
                    Text(visibility.name).tag(visibility)
                }
            }
        #else
            Button(self.visibility.name) {
                self.visibility = self.visibility.next()
            }
            .contextMenu {
                ForEach(Playlist.Visibility.allCases) { visibility in
                    Button(visibility.name) {
                        self.visibility = visibility
                    }
                }

                #if os(tvOS)
                    Button("Cancel", role: .cancel) {}
                #endif
            }
        #endif
    }

    var deletePlaylistButton: some View {
        Button("Delete") {
            presentingDeleteConfirmation = true
        }
        .alert(isPresented: $presentingDeleteConfirmation) {
            Alert(
                title: Text("Are you sure you want to delete playlist?"),
                message: Text("Playlist \"\(playlist.title)\" will be deleted.\nIt cannot be reverted."),
                primaryButton: .destructive(Text("Delete"), action: deletePlaylistAndDismiss),
                secondaryButton: .cancel()
            )
        }
        .foregroundColor(.red)
    }

    func deletePlaylistAndDismiss() {
        accounts.api.deletePlaylist(playlist, onFailure: { error in
            formError = "(\(error.httpStatusCode ?? -1)) \(error.localizedDescription)"
            presentingErrorAlert = true
        }) {
            playlist = nil
            playlists.load(force: true)
            presentationMode.wrappedValue.dismiss()
        }
    }
}

struct PlaylistFormView_Previews: PreviewProvider {
    static var previews: some View {
        PlaylistFormView(playlist: .constant(Playlist.fixture))
    }
}