#if os(macOS) && canImport(FlutterMacOS)
import Cocoa
import FlutterMacOS
import UniformTypeIdentifiers

enum EntitlementMode {
    case requireWrite
    case readOrWrite
}

private extension CFString {
    static let securityFilesUserSelectedReadOnly =
        "com.apple.security.files.user-selected.read-only" as CFString
    static let securityFilesUserSelectedReadWrite =
        "com.apple.security.files.user-selected.read-write" as CFString
}

final class MacOSFilePickerHandler {
    private let registrar: FlutterPluginRegistrar
    private var skipEntitlementsChecks: Bool = false

    init(registrar: FlutterPluginRegistrar) {
        self.registrar = registrar
    }

    func handle(_ call: FlutterMethodCall, result: @escaping FlutterResult) {
        switch call.method {
        case "pickFiles":
            handleFileSelection(call, result: result)

        case "getDirectoryPath":
            handleDirectorySelection(call, result: result)

        case "pickFileAndDirectoryPaths":
            handleFileAndDirectorySelection(call, result: result)

        case "saveFile":
            handleSaveFile(call, result: result)

        case "skipEntitlementsChecks":
            skipEntitlementsChecks = true
            result(nil)

        default:
            result(FlutterMethodNotImplemented)
        }
    }

    private func handleFileSelection(
        _ call: FlutterMethodCall,
        result: @escaping FlutterResult
    ) {
        if let entitlementError = checkEntitlement(requiredMode: .readOrWrite) {
            result(entitlementError)
            return
        }
        let dialog = NSOpenPanel()
        let args = call.arguments as! [String: Any]

        if let initialDirectory = args["initialDirectory"] as? String,
           !initialDirectory.isEmpty {
            dialog.directoryURL = URL(fileURLWithPath: initialDirectory)
        }
        if let title = args["dialogTitle"] as? String {
            dialog.title = title
            dialog.message = title
        }
        dialog.showsHiddenFiles = false
        let allowMultiple = args["allowMultiple"] as? Bool ?? false
        dialog.allowsMultipleSelection = allowMultiple
        dialog.canChooseDirectories = false
        dialog.canChooseFiles = true
        let extensions = args["allowedExtensions"] as? [String] ?? []
        applyExtensions(dialog, extensions)

        guard let appWindow = getFlutterWindow() else {
            result(nil)
            return
        }

        dialog.beginSheetModal(for: appWindow) { response in
            if response != .OK {
                result(nil)
                return
            }

            if allowMultiple {
                let pathResult = dialog.urls

                if pathResult.isEmpty {
                    result(nil)
                } else {
                    let paths = pathResult.map { $0.path }
                    result(paths)
                }
                return
            }

            if let pathResult = dialog.url {
                result([pathResult.path])
                return
            }

            result(nil)
        }
    }

    private func handleFileAndDirectorySelection(
        _ call: FlutterMethodCall,
        result: @escaping FlutterResult
    ) {
        if let entitlementError = checkEntitlement(requiredMode: .readOrWrite) {
            result(entitlementError)
            return
        }

        let dialog: NSOpenPanel = NSOpenPanel()
        let args = call.arguments as! [String: Any]

        if let initialDirectory = args["initialDirectory"] as? String,
           !initialDirectory.isEmpty {
            dialog.directoryURL = URL(fileURLWithPath: initialDirectory)
        }
        if let title = args["dialogTitle"] as? String {
            dialog.title = title
            dialog.message = title
        }
        dialog.showsHiddenFiles = false
        dialog.allowsMultipleSelection = true
        dialog.canChooseDirectories = true
        dialog.canChooseFiles = true
        let extensions = args["allowedExtensions"] as? [String] ?? []
        applyExtensions(dialog, extensions)

        guard let appWindow: NSWindow = getFlutterWindow() else {
            result(nil)
            return
        }

        dialog.beginSheetModal(for: appWindow) { response in
            if response != .OK {
                result(nil)
                return
            }

            let pathResult = dialog.urls

            if pathResult.isEmpty {
                result(nil)
            } else {
                let paths = pathResult.map { $0.path }
                result(paths)
            }
        }
    }

    private func handleDirectorySelection(
        _ call: FlutterMethodCall,
        result: @escaping FlutterResult
    ) {
        if let entitlementError = checkEntitlement(requiredMode: .readOrWrite) {
            result(entitlementError)
            return
        }

        let dialog = NSOpenPanel()
        let args = call.arguments as! [String: Any]

        if let initialDirectory = args["initialDirectory"] as? String,
           !initialDirectory.isEmpty {
            dialog.directoryURL = URL(fileURLWithPath: initialDirectory)
        }
        if let title = args["dialogTitle"] as? String {
            dialog.title = title
            if #available(macOS 10.10, *) {
                dialog.titleVisibility = .visible
                dialog.titlebarAppearsTransparent = false
            }
            dialog.message = title
        }
        dialog.showsHiddenFiles = false
        dialog.allowsMultipleSelection = false
        dialog.canChooseDirectories = true
        dialog.canChooseFiles = false

        guard let appWindow = getFlutterWindow() else {
            result(nil)
            return
        }
        dialog.beginSheetModal(for: appWindow) { response in
            if response != .OK {
                result(nil)
                return
            }

            if let url = dialog.url {
                result(url.path)
                return
            }

            result(nil)
        }
    }

    private func handleSaveFile(
        _ call: FlutterMethodCall,
        result: @escaping FlutterResult
    ) {
        if let entitlementError = checkEntitlement(requiredMode: .requireWrite) {
            result(entitlementError)
            return
        }

        let dialog = NSSavePanel()
        let args = call.arguments as! [String: Any]

        dialog.title = args["dialogTitle"] as? String ?? ""
        dialog.showsTagField = false
        dialog.showsHiddenFiles = false
        dialog.canCreateDirectories = true
        dialog.nameFieldStringValue = args["fileName"] as? String ?? ""

        if let initialDirectory = args["initialDirectory"] as? String,
           !initialDirectory.isEmpty {
            dialog.directoryURL = URL(fileURLWithPath: initialDirectory)
        }

        let extensions = args["allowedExtensions"] as? [String] ?? []
        applyExtensions(dialog, extensions)

        guard let appWindow = getFlutterWindow() else {
            result(nil)
            return
        }
        dialog.beginSheetModal(for: appWindow) { response in
            if response != .OK {
                result(nil)
                return
            }

            if let url = dialog.url {
                result(url.path)
                return
            }

            result(nil)
        }
    }

    private func checkEntitlement(requiredMode: EntitlementMode) -> FlutterError? {
        if skipEntitlementsChecks {
            return nil
        }

        guard let task = SecTaskCreateFromSelf(nil) else {
            return FlutterError(
                code: "ENTITLEMENT_CHECK_FAILED",
                message: "Failed to verify file_picker entitlements.",
                details: nil)
        }

        let readWriteEntitlement =
            SecTaskCopyValueForEntitlement(
                task,
                .securityFilesUserSelectedReadWrite,
                nil) as? Bool
        let readOnlyEntitlement =
            SecTaskCopyValueForEntitlement(
                task,
                .securityFilesUserSelectedReadOnly,
                nil) as? Bool

        switch requiredMode {
        case .requireWrite:
            if readWriteEntitlement != true {
                return FlutterError(
                    code: "ENTITLEMENT_REQUIRED_WRITE",
                    message:
                        "The Read-Write entitlement is required for this action.",
                    details: nil)
            }

        case .readOrWrite:
            if readWriteEntitlement != true && readOnlyEntitlement != true {
                return FlutterError(
                    code: "ENTITLEMENT_NOT_FOUND",
                    message:
                        "Either the Read-Only or Read-Write entitlement is required for this action.",
                    details: nil)
            }
        }
        return nil
    }

    private func applyExtensions(_ dialog: NSSavePanel, _ extensions: [String]) {
        if !extensions.isEmpty {
            if #available(macOS 11.0, *) {
                let contentTypes = extensions.compactMap { ext in
                    UTType(filenameExtension: ext)
                }
                dialog.allowedContentTypes = contentTypes
            } else {
                dialog.allowedFileTypes = extensions
            }
        }
    }

    private func getFlutterWindow() -> NSWindow? {
        registrar.view?.window
    }
}
#endif
