#include "plugin/windows_native_files.h"

#include <flutter/method_call.h>
#include <flutter/method_result.h>
#include <flutter/standard_method_codec.h>
#include <appmodel.h>
#include <knownfolders.h>
#include <shlobj.h>
#include <shobjidl.h>
#include <windows.h>
#include <wrl/client.h>

#include <algorithm>
#include <cctype>
#include <cstdint>
#include <cwctype>
#include <filesystem>
#include <iomanip>
#include <iterator>
#include <set>
#include <sstream>
#include <system_error>
#include <utility>

#include "util/string_converter.h"

namespace coreframe_flutter_windows {
namespace {

using Microsoft::WRL::ComPtr;

constexpr auto kChannelName = "coreframe/native_files";
constexpr auto kStorageDirectory = L"Coreframe\\native-files";
constexpr int64_t kWindowsEpochOffsetMilliseconds = 11644473600000LL;
constexpr int64_t kStaleAfterMilliseconds = 24LL * 60 * 60 * 1000;

class ScopedHandle {
public:
  explicit ScopedHandle(HANDLE handle = INVALID_HANDLE_VALUE)
      : handle_(handle) {}
  ~ScopedHandle() {
    if (handle_ != INVALID_HANDLE_VALUE) {
      CloseHandle(handle_);
    }
  }
  ScopedHandle(const ScopedHandle &) = delete;
  ScopedHandle &operator=(const ScopedHandle &) = delete;
  HANDLE get() const { return handle_; }
  void Close() {
    if (handle_ != INVALID_HANDLE_VALUE) {
      CloseHandle(handle_);
      handle_ = INVALID_HANDLE_VALUE;
    }
  }

private:
  HANDLE handle_;
};

class ScopedFindHandle {
public:
  explicit ScopedFindHandle(HANDLE handle) : handle_(handle) {}
  ~ScopedFindHandle() {
    if (handle_ != INVALID_HANDLE_VALUE) {
      FindClose(handle_);
    }
  }
  ScopedFindHandle(const ScopedFindHandle &) = delete;
  ScopedFindHandle &operator=(const ScopedFindHandle &) = delete;
  HANDLE get() const { return handle_; }

private:
  HANDLE handle_;
};

bool IsFilterCharacter(char value) {
  return std::isalnum(static_cast<unsigned char>(value)) != 0 || value == '!' ||
         value == '#' || value == '$' || value == '&' || value == '^' ||
         value == '_' || value == '.' || value == '+' || value == '-';
}

bool IsValidFilter(const std::string &value) {
  if (value.size() >= 2 && value.size() <= 33 && value.front() == '.') {
    if (std::isalnum(static_cast<unsigned char>(value[1])) == 0) {
      return false;
    }
    return std::all_of(value.begin() + 2, value.end(), [](char character) {
      return std::isalnum(static_cast<unsigned char>(character)) != 0 ||
             character == '.' || character == '_' || character == '+' ||
             character == '-';
    });
  }
  const auto slash = value.find('/');
  if (slash == std::string::npos || slash == 0 || slash == value.size() - 1 ||
      value.find('/', slash + 1) != std::string::npos) {
    return false;
  }
  const bool valid_type =
      std::all_of(value.begin(), value.begin() + slash, IsFilterCharacter);
  const auto subtype = value.substr(slash + 1);
  return valid_type &&
         (subtype == "*" ||
          std::all_of(subtype.begin(), subtype.end(), IsFilterCharacter));
}

struct PickRequest {
  std::vector<std::string> accept;
  bool multiple;
};

std::optional<PickRequest>
ParsePickRequest(const flutter::EncodableValue *arguments) {
  if (!arguments) {
    return std::nullopt;
  }
  const auto *map = std::get_if<flutter::EncodableMap>(arguments);
  if (!map || map->size() != 2) {
    return std::nullopt;
  }
  const auto accept_entry = map->find(flutter::EncodableValue("accept"));
  const auto multiple_entry = map->find(flutter::EncodableValue("multiple"));
  if (accept_entry == map->end() || multiple_entry == map->end()) {
    return std::nullopt;
  }
  const auto *accept =
      std::get_if<flutter::EncodableList>(&accept_entry->second);
  const auto *multiple = std::get_if<bool>(&multiple_entry->second);
  if (!accept || !multiple ||
      accept->size() > WindowsNativeFileStager::kMaximumFiles) {
    return std::nullopt;
  }
  PickRequest request{{}, *multiple};
  request.accept.reserve(accept->size());
  for (const auto &value : *accept) {
    const auto *filter = std::get_if<std::string>(&value);
    if (!filter || !IsValidFilter(*filter)) {
      return std::nullopt;
    }
    request.accept.push_back(*filter);
  }
  return request;
}

std::wstring Lowercase(std::wstring value) {
  std::transform(value.begin(), value.end(), value.begin(),
                 [](wchar_t character) { return std::towlower(character); });
  return value;
}

std::string Lowercase(std::string value) {
  std::transform(value.begin(), value.end(), value.begin(), [](char character) {
    return static_cast<char>(
        std::tolower(static_cast<unsigned char>(character)));
  });
  return value;
}

std::optional<std::wstring> ExtensionForMimeType(const std::string &mime_type) {
  const auto key =
      util::Utf16FromUtf8("MIME\\Database\\Content Type\\" + mime_type);
  wchar_t extension[64] = {};
  DWORD bytes = sizeof(extension);
  const auto status = RegGetValueW(HKEY_CLASSES_ROOT, key.c_str(), L"Extension",
                                   RRF_RT_REG_SZ, nullptr, extension, &bytes);
  if (status != ERROR_SUCCESS || extension[0] != L'.') {
    return std::nullopt;
  }
  return std::wstring(L"*") + extension;
}

std::vector<std::wstring>
ComputePatternsForAccept(const std::vector<std::string> &accept) {
  std::set<std::wstring> patterns;
  for (const auto &raw_filter : accept) {
    const auto filter = Lowercase(raw_filter);
    if (filter.front() == '.') {
      patterns.insert(L"*" + Lowercase(util::Utf16FromUtf8(filter)));
      continue;
    }
    if (filter == "image/*") {
      for (const auto *pattern :
           {L"*.avif", L"*.bmp", L"*.gif", L"*.heic", L"*.jpeg", L"*.jpg",
            L"*.png", L"*.tif", L"*.tiff", L"*.webp"}) {
        patterns.insert(pattern);
      }
      continue;
    }
    if (filter == "audio/*") {
      for (const auto *pattern : {L"*.aac", L"*.flac", L"*.m4a", L"*.mp3",
                                  L"*.ogg", L"*.wav", L"*.wma"}) {
        patterns.insert(pattern);
      }
      continue;
    }
    if (filter == "video/*") {
      for (const auto *pattern : {L"*.avi", L"*.m4v", L"*.mkv", L"*.mov",
                                  L"*.mp4", L"*.mpeg", L"*.webm", L"*.wmv"}) {
        patterns.insert(pattern);
      }
      continue;
    }
    if (filter == "text/*") {
      for (const auto *pattern :
           {L"*.csv", L"*.htm", L"*.html", L"*.json", L"*.md", L"*.rtf",
            L"*.text", L"*.txt", L"*.xml"}) {
        patterns.insert(pattern);
      }
      continue;
    }
    if (const auto extension = ExtensionForMimeType(filter)) {
      patterns.insert(Lowercase(*extension));
      continue;
    }
    continue;
  }
  return std::vector<std::wstring>(patterns.begin(), patterns.end());
}

std::wstring JoinPatterns(const std::vector<std::wstring> &patterns) {
  std::wstring value;
  for (const auto &pattern : patterns) {
    if (!value.empty()) {
      value += L';';
    }
    value += pattern;
  }
  return value;
}

std::optional<std::wstring> ExecutablePath() {
  std::vector<wchar_t> executable_path(MAX_PATH);
  while (true) {
    const DWORD length =
        GetModuleFileNameW(nullptr, executable_path.data(),
                           static_cast<DWORD>(executable_path.size()));
    if (length == 0) {
      return std::nullopt;
    }
    if (length < executable_path.size() - 1) {
      return std::wstring(executable_path.data(), length);
    }
    executable_path.resize(executable_path.size() * 2);
  }
}

std::optional<std::wstring> ApplicationIdentity() {
  UINT32 family_length = 0;
  if (GetCurrentPackageFamilyName(&family_length, nullptr) ==
          ERROR_INSUFFICIENT_BUFFER &&
      family_length > 1) {
    std::vector<wchar_t> family(family_length);
    if (GetCurrentPackageFamilyName(&family_length, family.data()) ==
        ERROR_SUCCESS) {
      return std::wstring(family.data());
    }
  }
  const auto executable = ExecutablePath();
  if (!executable) {
    return std::nullopt;
  }
  uint64_t hash = 14695981039346656037ULL;
  for (const wchar_t character : *executable) {
    hash ^= static_cast<uint64_t>(character);
    hash *= 1099511628211ULL;
  }
  std::wostringstream value;
  value << L"executable-" << std::hex << std::setw(16) << std::setfill(L'0')
        << hash;
  return value.str();
}

std::optional<std::wstring> StorageNamespace() {
  PWSTR local_app_data = nullptr;
  if (FAILED(SHGetKnownFolderPath(FOLDERID_LocalAppData, KF_FLAG_CREATE,
                                  nullptr, &local_app_data)) ||
      !local_app_data) {
    return std::nullopt;
  }
  std::filesystem::path path(local_app_data);
  CoTaskMemFree(local_app_data);
  path /= kStorageDirectory;
  const auto identity = ApplicationIdentity();
  if (!identity) {
    return std::nullopt;
  }
  auto application = *identity;
  for (auto &character : application) {
    if (std::iswalnum(character) == 0 && character != L'-' &&
        character != L'_' && character != L'.') {
      character = L'_';
    }
  }
  if (application.empty() || application == L"." || application == L"..") {
    application = L"application";
  }
  path /= application.substr(0, 128);
  return path.wstring();
}

std::wstring UniqueDestination(const std::wstring &directory) {
  GUID guid = {};
  if (FAILED(CoCreateGuid(&guid))) {
    return {};
  }
  wchar_t value[40] = {};
  if (StringFromGUID2(guid, value, static_cast<int>(std::size(value))) <= 0) {
    return {};
  }
  std::wstring name(value);
  name.erase(std::remove(name.begin(), name.end(), L'{'), name.end());
  name.erase(std::remove(name.begin(), name.end(), L'}'), name.end());
  return (std::filesystem::path(directory) / name).wstring();
}

std::optional<int64_t> LastModifiedMilliseconds(const FILETIME &file_time) {
  ULARGE_INTEGER ticks = {};
  ticks.LowPart = file_time.dwLowDateTime;
  ticks.HighPart = file_time.dwHighDateTime;
  const uint64_t milliseconds = ticks.QuadPart / 10000;
  if (milliseconds < static_cast<uint64_t>(kWindowsEpochOffsetMilliseconds)) {
    return std::nullopt;
  }
  const uint64_t unix_milliseconds =
      milliseconds - kWindowsEpochOffsetMilliseconds;
  if (unix_milliseconds > static_cast<uint64_t>(INT64_MAX)) {
    return std::nullopt;
  }
  return static_cast<int64_t>(unix_milliseconds);
}

std::optional<std::string> MediaTypeForPath(const std::wstring &path) {
  const auto extension = std::filesystem::path(path).extension().wstring();
  if (extension.empty()) {
    return std::nullopt;
  }
  wchar_t content_type[256] = {};
  DWORD bytes = sizeof(content_type);
  const auto status =
      RegGetValueW(HKEY_CLASSES_ROOT, extension.c_str(), L"Content Type",
                   RRF_RT_REG_SZ, nullptr, content_type, &bytes);
  if (status != ERROR_SUCCESS || content_type[0] == L'\0') {
    return std::nullopt;
  }
  const auto value = util::Utf8FromUtf16(content_type);
  return value.empty() ? std::nullopt : std::optional<std::string>(value);
}

std::string SafeName(const std::wstring &name) {
  const auto limited = name.substr(0, 1024);
  const auto value = util::Utf8FromUtf16(limited);
  return value.empty() ? "file" : value;
}

bool CopyBounded(HANDLE source, HANDLE destination, int64_t maximum_bytes,
                 int64_t *copied_bytes) {
  std::vector<uint8_t> buffer(64 * 1024);
  int64_t total = 0;
  while (true) {
    DWORD read = 0;
    if (!ReadFile(source, buffer.data(), static_cast<DWORD>(buffer.size()),
                  &read, nullptr)) {
      return false;
    }
    if (read == 0) {
      *copied_bytes = total;
      return true;
    }
    if (total > maximum_bytes - static_cast<int64_t>(read)) {
      SetLastError(ERROR_FILE_TOO_LARGE);
      return false;
    }
    DWORD written = 0;
    while (written < read) {
      DWORD next = 0;
      if (!WriteFile(destination, buffer.data() + written, read - written,
                     &next, nullptr) ||
          next == 0) {
        return false;
      }
      written += next;
    }
    total += read;
  }
}

WindowsNativeFileStagingResult
StagingFailure(WindowsNativeFileStagingFailure failure,
               std::vector<WindowsStagedNativeFile> files = {}) {
  WindowsNativeFileStager::Remove(files);
  return {{}, failure};
}

void RemovePath(const std::string &path) {
  const auto wide_path = util::Utf16FromUtf8(path);
  if (!wide_path.empty()) {
    DeleteFileW(wide_path.c_str());
  }
}

std::vector<WindowsNativeFileSelection>
SelectionsFromDialog(IFileOpenDialog *dialog) {
  ComPtr<IShellItemArray> items;
  if (FAILED(dialog->GetResults(&items)) || !items) {
    return {};
  }
  DWORD count = 0;
  if (FAILED(items->GetCount(&count))) {
    return {};
  }
  std::vector<WindowsNativeFileSelection> selections;
  selections.reserve(count);
  for (DWORD index = 0; index < count; ++index) {
    ComPtr<IShellItem> item;
    PWSTR path = nullptr;
    if (FAILED(items->GetItemAt(index, &item)) || !item ||
        FAILED(item->GetDisplayName(SIGDN_FILESYSPATH, &path)) || !path) {
      return {};
    }
    std::filesystem::path source(path);
    CoTaskMemFree(path);
    selections.push_back({source.wstring(), source.filename().wstring()});
  }
  return selections;
}

} // namespace

std::vector<std::wstring>
WindowsPatternsForAccept(const std::vector<std::string> &accept) {
  return ComputePatternsForAccept(accept);
}

flutter::EncodableValue WindowsStagedNativeFile::ToChannelValue() const {
  flutter::EncodableMap value{
      {flutter::EncodableValue("name"), flutter::EncodableValue(name)},
      {flutter::EncodableValue("size"), flutter::EncodableValue(size)},
      {flutter::EncodableValue("stagedPath"),
       flutter::EncodableValue(staged_path)},
      {flutter::EncodableValue("lastModifiedMilliseconds"),
       last_modified_milliseconds
           ? flutter::EncodableValue(*last_modified_milliseconds)
           : flutter::EncodableValue()},
      {flutter::EncodableValue("mediaType"),
       media_type ? flutter::EncodableValue(*media_type)
                  : flutter::EncodableValue()},
  };
  return flutter::EncodableValue(value);
}

WindowsNativeFileStager::WindowsNativeFileStager(std::wstring staging_directory,
                                                 size_t maximum_files,
                                                 int64_t maximum_file_bytes,
                                                 int64_t maximum_total_bytes)
    : staging_directory_(std::move(staging_directory)),
      maximum_files_(maximum_files), maximum_file_bytes_(maximum_file_bytes),
      maximum_total_bytes_(maximum_total_bytes) {}

WindowsNativeFileStagingResult WindowsNativeFileStager::Stage(
    const std::vector<WindowsNativeFileSelection> &selections) const {
  if (selections.size() > maximum_files_) {
    return StagingFailure(WindowsNativeFileStagingFailure::kCapacityExceeded);
  }
  std::error_code directory_error;
  std::filesystem::create_directories(staging_directory_, directory_error);
  if (directory_error) {
    return StagingFailure(WindowsNativeFileStagingFailure::kUnreadable);
  }

  int64_t total_bytes = 0;
  std::vector<WindowsStagedNativeFile> staged;
  staged.reserve(selections.size());
  for (const auto &selection : selections) {
    WIN32_FILE_ATTRIBUTE_DATA attributes = {};
    if (!GetFileAttributesExW(selection.source_path.c_str(),
                              GetFileExInfoStandard, &attributes) ||
        (attributes.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
      return StagingFailure(WindowsNativeFileStagingFailure::kUnreadable,
                            std::move(staged));
    }
    ULARGE_INTEGER declared_size = {};
    declared_size.LowPart = attributes.nFileSizeLow;
    declared_size.HighPart = attributes.nFileSizeHigh;
    if (declared_size.QuadPart > static_cast<uint64_t>(maximum_file_bytes_) ||
        declared_size.QuadPart >
            static_cast<uint64_t>(maximum_total_bytes_ - total_bytes)) {
      return StagingFailure(WindowsNativeFileStagingFailure::kCapacityExceeded,
                            std::move(staged));
    }

    ScopedHandle source(CreateFileW(
        selection.source_path.c_str(), GENERIC_READ,
        FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr,
        OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
        nullptr));
    const auto destination_path = UniqueDestination(staging_directory_);
    ScopedHandle destination(
        destination_path.empty()
            ? INVALID_HANDLE_VALUE
            : CreateFileW(destination_path.c_str(), GENERIC_WRITE, 0, nullptr,
                          CREATE_NEW, FILE_ATTRIBUTE_TEMPORARY, nullptr));
    if (source.get() == INVALID_HANDLE_VALUE ||
        destination.get() == INVALID_HANDLE_VALUE) {
      if (!destination_path.empty()) {
        destination.Close();
        DeleteFileW(destination_path.c_str());
      }
      return StagingFailure(WindowsNativeFileStagingFailure::kUnreadable,
                            std::move(staged));
    }

    const int64_t maximum_bytes =
        std::min(maximum_file_bytes_, maximum_total_bytes_ - total_bytes);
    int64_t copied_bytes = 0;
    if (!CopyBounded(source.get(), destination.get(), maximum_bytes,
                     &copied_bytes)) {
      const auto copy_error = GetLastError();
      destination.Close();
      DeleteFileW(destination_path.c_str());
      return StagingFailure(
          copy_error == ERROR_FILE_TOO_LARGE
              ? WindowsNativeFileStagingFailure::kCapacityExceeded
              : WindowsNativeFileStagingFailure::kUnreadable,
          std::move(staged));
    }
    if (copied_bytes != static_cast<int64_t>(declared_size.QuadPart)) {
      destination.Close();
      DeleteFileW(destination_path.c_str());
      return StagingFailure(WindowsNativeFileStagingFailure::kUnreadable,
                            std::move(staged));
    }

    total_bytes += copied_bytes;
    staged.push_back({SafeName(selection.name), copied_bytes,
                      util::Utf8FromUtf16(destination_path),
                      LastModifiedMilliseconds(attributes.ftLastWriteTime),
                      MediaTypeForPath(selection.source_path)});
  }
  return {std::move(staged), std::nullopt};
}

void WindowsNativeFileStager::Remove(
    const std::vector<WindowsStagedNativeFile> &files) {
  for (const auto &file : files) {
    RemovePath(file.staged_path);
  }
}

void WindowsNativeFileStager::SweepStale(
    const std::wstring &staging_directory) {
  FILETIME now = {};
  GetSystemTimeAsFileTime(&now);
  ULARGE_INTEGER cutoff = {};
  cutoff.LowPart = now.dwLowDateTime;
  cutoff.HighPart = now.dwHighDateTime;
  const uint64_t stale_ticks =
      static_cast<uint64_t>(kStaleAfterMilliseconds) * 10000;
  cutoff.QuadPart =
      cutoff.QuadPart > stale_ticks ? cutoff.QuadPart - stale_ticks : 0;

  WIN32_FIND_DATAW entry = {};
  const auto pattern =
      (std::filesystem::path(staging_directory) / L"*").wstring();
  ScopedFindHandle search(FindFirstFileW(pattern.c_str(), &entry));
  if (search.get() == INVALID_HANDLE_VALUE) {
    return;
  }
  do {
    if ((entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0) {
      continue;
    }
    ULARGE_INTEGER modified = {};
    modified.LowPart = entry.ftLastWriteTime.dwLowDateTime;
    modified.HighPart = entry.ftLastWriteTime.dwHighDateTime;
    if (modified.QuadPart <= cutoff.QuadPart) {
      DeleteFileW((std::filesystem::path(staging_directory) / entry.cFileName)
                      .wstring()
                      .c_str());
    }
  } while (FindNextFileW(search.get(), &entry));
}

struct WindowsNativeFiles::PendingPick {
  explicit PendingPick(
      std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> value)
      : result(std::move(value)) {}
  std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result;
};

struct WindowsNativeFiles::Completion {
  WindowsNativeFileStagingResult staging;
};

WindowsNativeFiles::WindowsNativeFiles(
    flutter::PluginRegistrarWindows *registrar)
    : registrar_(registrar) {
  const auto storage = StorageNamespace();
  if (storage) {
    staging_directory_ =
        (std::filesystem::path(*storage) / L"staging").wstring();
    resource_storage_root_ =
        (std::filesystem::path(*storage) / L"resources").wstring();
  }
  auto *view = registrar_->GetView();
  const auto view_window = view ? view->GetNativeWindow() : nullptr;
  window_ = view_window ? GetAncestor(view_window, GA_ROOT) : nullptr;
  if (!window_) {
    window_ = view_window;
  }
  completion_message_ =
      RegisterWindowMessageW(L"Coreframe.NativeFiles.StagingComplete");
  channel_ = std::make_unique<flutter::MethodChannel<flutter::EncodableValue>>(
      registrar_->messenger(), kChannelName,
      &flutter::StandardMethodCodec::GetInstance());
  channel_->SetMethodCallHandler(
      [this](const flutter::MethodCall<flutter::EncodableValue> &call,
             std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>>
                 result) { HandleMethodCall(call, std::move(result)); });
  window_proc_delegate_id_ = registrar_->RegisterTopLevelWindowProcDelegate(
      [this](HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam) {
        return HandleWindowMessage(hwnd, message, wparam, lparam);
      });
  if (!staging_directory_.empty()) {
    workers_.emplace_back([directory = staging_directory_]() {
      WindowsNativeFileStager::SweepStale(directory);
    });
  }
}

WindowsNativeFiles::~WindowsNativeFiles() {
  attached_ = false;
  channel_->SetMethodCallHandler(nullptr);
  if (window_proc_delegate_id_ >= 0) {
    registrar_->UnregisterTopLevelWindowProcDelegate(window_proc_delegate_id_);
  }
  for (auto &worker : workers_) {
    if (worker.joinable()) {
      worker.join();
    }
  }
  std::unique_ptr<Completion> completion;
  {
    std::lock_guard<std::mutex> lock(completion_mutex_);
    completion = std::move(completion_);
  }
  if (completion) {
    WindowsNativeFileStager::Remove(completion->staging.files);
  }
  if (pending_) {
    pending_->result->Error("internal",
                            "Native file selection was interrupted.");
  }
}

void WindowsNativeFiles::HandleMethodCall(
    const flutter::MethodCall<flutter::EncodableValue> &call,
    std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
  if (call.method_name() == "isAvailable") {
    result->Success(flutter::EncodableValue(window_ != nullptr &&
                                            !staging_directory_.empty()));
  } else if (call.method_name() == "getResourceStorageRoot") {
    std::error_code error;
    if (!resource_storage_root_.empty() &&
        (std::filesystem::create_directories(resource_storage_root_, error) ||
         std::filesystem::is_directory(resource_storage_root_, error))) {
      result->Success(flutter::EncodableValue(
          util::Utf8FromUtf16(resource_storage_root_)));
    } else {
      result->Success(flutter::EncodableValue());
    }
  } else if (call.method_name() == "pick") {
    Pick(call.arguments(), std::move(result));
  } else {
    result->NotImplemented();
  }
}

void WindowsNativeFiles::Pick(
    const flutter::EncodableValue *arguments,
    std::unique_ptr<flutter::MethodResult<flutter::EncodableValue>> result) {
  if (pending_) {
    result->Error("picker_busy", "A native file picker is already active.");
    return;
  }
  if (!window_ || staging_directory_.empty()) {
    result->Error("unsupported_platform",
                  "Native file selection is unavailable on this host.");
    return;
  }
  const auto request = ParsePickRequest(arguments);
  if (!request) {
    result->Error("internal", "The native file request is invalid.");
    return;
  }
  const auto patterns = WindowsPatternsForAccept(request->accept);
  pending_ = std::make_unique<PendingPick>(std::move(result));

  ComPtr<IFileOpenDialog> dialog;
  auto status = CoCreateInstance(CLSID_FileOpenDialog, nullptr,
                                 CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&dialog));
  if (FAILED(status) || !dialog) {
    pending_->result->Error("unsupported_platform",
                            "The Windows file picker is unavailable.");
    pending_.reset();
    return;
  }
  FILEOPENDIALOGOPTIONS options = {};
  dialog->GetOptions(&options);
  options |= FOS_FILEMUSTEXIST | FOS_PATHMUSTEXIST | FOS_NOCHANGEDIR |
             FOS_FORCEFILESYSTEM;
  if (request->multiple) {
    options |= FOS_ALLOWMULTISELECT;
  }
  dialog->SetOptions(options);
  const auto joined_patterns = JoinPatterns(patterns);
  if (!joined_patterns.empty()) {
    const COMDLG_FILTERSPEC filter = {L"Accepted files",
                                      joined_patterns.c_str()};
    dialog->SetFileTypes(1, &filter);
  }

  status = dialog->Show(window_);
  if (status == HRESULT_FROM_WIN32(ERROR_CANCELLED)) {
    pending_->result->Success(
        flutter::EncodableValue(flutter::EncodableList{}));
    pending_.reset();
    return;
  }
  if (FAILED(status)) {
    pending_->result->Error("internal", "Native file selection failed.");
    pending_.reset();
    return;
  }
  auto selections = SelectionsFromDialog(dialog.Get());
  if (selections.empty()) {
    pending_->result->Error("unreadable_selection",
                            "A selected file could not be read.");
    pending_.reset();
    return;
  }
  if (selections.size() > WindowsNativeFileStager::kMaximumFiles) {
    pending_->result->Error("capacity_exceeded",
                            "Too many files were selected.");
    pending_.reset();
    return;
  }

  try {
    workers_.emplace_back([this, selections = std::move(selections)]() mutable {
      WindowsNativeFileStager stager(staging_directory_);
      auto completion = std::make_unique<Completion>();
      completion->staging = stager.Stage(selections);
      {
        std::lock_guard<std::mutex> lock(completion_mutex_);
        if (!attached_) {
          WindowsNativeFileStager::Remove(completion->staging.files);
          return;
        }
        completion_ = std::move(completion);
      }
      PostMessageW(window_, completion_message_, 0, 0);
    });
  } catch (const std::system_error &) {
    pending_->result->Error("internal", "Native file selection failed.");
    pending_.reset();
  }
}

std::optional<LRESULT> WindowsNativeFiles::HandleWindowMessage(HWND hwnd,
                                                               UINT message,
                                                               WPARAM, LPARAM) {
  if (completion_message_ == 0 || message != completion_message_ ||
      hwnd != window_) {
    return std::nullopt;
  }
  CompletePending();
  return 0;
}

void WindowsNativeFiles::CompletePending() {
  std::unique_ptr<Completion> completion;
  {
    std::lock_guard<std::mutex> lock(completion_mutex_);
    completion = std::move(completion_);
  }
  if (!completion || !pending_) {
    if (completion) {
      WindowsNativeFileStager::Remove(completion->staging.files);
    }
    return;
  }
  if (completion->staging.failure) {
    const bool capacity = *completion->staging.failure ==
                          WindowsNativeFileStagingFailure::kCapacityExceeded;
    pending_->result->Error(
        capacity ? "capacity_exceeded" : "unreadable_selection",
        capacity ? "The native file staging limit was exceeded."
                 : "A selected file could not be read.");
    pending_.reset();
    return;
  }
  flutter::EncodableList files;
  files.reserve(completion->staging.files.size());
  for (const auto &file : completion->staging.files) {
    files.push_back(file.ToChannelValue());
  }
  // Once the channel response is sent, Dart owns and eventually removes every
  // staged path. All earlier failure and teardown paths remain native-owned.
  pending_->result->Success(flutter::EncodableValue(files));
  pending_.reset();
}

} // namespace coreframe_flutter_windows
