import ApplicationLibrary
import Library
import SwiftUI

struct EditProfileContentWindow: View {
    let context: EditProfileContentView.Context?

    @StateObject private var viewModel: EditProfileContentViewModel
    @State private var showDiscardAlert = false
    @State private var windowState = WindowState()

    private let readOnly: Bool

    init(context: EditProfileContentView.Context?) {
        self.context = context
        readOnly = context?.readOnly == true
        _viewModel = StateObject(wrappedValue: EditProfileContentViewModel(profileID: context?.profileID))
    }

    @Environment(\.profileEditor) private var profileEditor

    var body: some View {
        Group {
            if viewModel.isLoading {
                ProgressView()
                    .frame(maxWidth: .infinity, maxHeight: .infinity)
                    .task {
                        await viewModel.loadContent()
                    }
            } else {
                editorView
                    .onChangeCompat(of: viewModel.profileContent) {
                        viewModel.markAsChanged()
                    }
            }
        }
        .frame(minWidth: 600, minHeight: 400)
        .background(WindowAccessor { window in
            guard let window else { return }
            if windowState.window == nil {
                windowState.window = window
                windowState.onClose = { [weak viewModel] in
                    viewModel?.reset()
                }
                let delegate = WindowCloseDelegate(
                    windowState: windowState,
                    hasUnsavedChanges: { [weak viewModel] in
                        viewModel?.isChanged == true
                    },
                    showAlert: {
                        showDiscardAlert = true
                    }
                )
                windowState.delegate = delegate
                window.delegate = delegate
            }
        })
        .onExitCommand {
            handleClose()
        }
        .alert("Unsaved Changes", isPresented: $showDiscardAlert) {
            Button("Don't Save", role: .destructive) {
                windowState.forceClose()
            }
            Button("Cancel", role: .cancel) {}
            if !readOnly {
                Button("Save") {
                    Task {
                        await viewModel.saveContent()
                        if viewModel.alert == nil {
                            windowState.forceClose()
                        }
                    }
                }
            }
        } message: {
            Text("Do you want to save the changes you made?")
        }
        .alert($viewModel.alert)
        .navigationTitle(navigationTitle)
        .toolbar {
            ToolbarItemGroup(placement: .navigation) {
                if !readOnly {
                    Button {
                        Task {
                            await viewModel.saveContent()
                        }
                    } label: {
                        Label("Save", image: "save")
                    }
                    .keyboardShortcut("s", modifiers: .command)
                    .disabled(!viewModel.isChanged)
                } else {
                    Button {
                        NSPasteboard.general.setString(viewModel.profileContent, forType: .string)
                    } label: {
                        Label("Copy", systemImage: "doc.on.clipboard")
                    }
                }
            }
        }
    }

    private var navigationTitle: String {
        if readOnly {
            return String(localized: "View Content")
        } else {
            return String(localized: "Edit Content")
        }
    }

    @ViewBuilder
    private var editorView: some View {
        if let profileEditor {
            profileEditor(
                readOnly ? .constant(viewModel.profileContent) : $viewModel.profileContent,
                !readOnly
            )
            .frame(maxWidth: .infinity, maxHeight: .infinity)
        } else {
            defaultEditorView
        }
    }

    private var defaultEditorView: some View {
        Group {
            if readOnly {
                TextEditor(text: .constant(viewModel.profileContent))
            } else {
                TextEditor(text: $viewModel.profileContent)
            }
        }
        .font(Font.system(.caption2, design: .monospaced))
        .autocorrectionDisabled(true)
        .textContentType(.init(rawValue: ""))
        .padding()
    }

    private func handleClose() {
        if viewModel.isChanged, !readOnly {
            showDiscardAlert = true
        } else {
            windowState.forceClose()
        }
    }
}

private class WindowState {
    weak var window: NSWindow?
    var delegate: WindowCloseDelegate?
    var onClose: (() -> Void)?

    func forceClose() {
        delegate?.allowClose = true
        window?.close()
    }
}

private class WindowCloseDelegate: NSObject, NSWindowDelegate {
    var allowClose = false
    private let windowState: WindowState
    private let hasUnsavedChanges: () -> Bool
    private let showAlert: () -> Void

    init(windowState: WindowState, hasUnsavedChanges: @escaping () -> Bool, showAlert: @escaping () -> Void) {
        self.windowState = windowState
        self.hasUnsavedChanges = hasUnsavedChanges
        self.showAlert = showAlert
        super.init()
    }

    func windowShouldClose(_: NSWindow) -> Bool {
        if allowClose {
            return true
        }
        if hasUnsavedChanges() {
            DispatchQueue.main.async {
                self.showAlert()
            }
            return false
        }
        return true
    }

    func windowWillClose(_: Notification) {
        windowState.onClose?()
        allowClose = false
    }
}
