#include "platform_apple/apple_platform_services.h"

#include "app_core/document_platform_io.h"
#include "platform_api/platform_policy.h"

#include <array>
#include <utility>

#if defined(__IOS__) || defined(__OSX__)
#include "app_core/app.h"
#include <dispatch/dispatch.h>
#endif

namespace pp::platform::apple {
namespace {

[[nodiscard]] std::vector<std::string> apple_image_file_types()
{
    static constexpr std::array<std::string_view, 5> kFileTypes = {
        "png",
        "PNG",
        "jpg",
        "JPG",
        "jpeg",
    };

    return { kFileTypes.begin(), kFileTypes.end() };
}

void invoke_picked_path_if_selected(
    const std::string& path,
    const PickedPathCallback& callback)
{
    if (pp::app::plan_picked_path(path) == pp::app::PickedPathAction::invoke_callback)
        callback(path);
}

}

AppleDocumentPlatformServices::AppleDocumentPlatformServices(
    PlatformFamily family,
    AppleDocumentPickerBridge bridge)
    : family_(family)
    , bridge_(std::move(bridge))
{
}

std::vector<std::string> AppleDocumentPlatformServices::document_browse_roots(
    std::string_view work_path,
    std::string_view data_path) const
{
    return platform_document_browse_roots(family_, work_path, data_path);
}

std::string AppleDocumentPlatformServices::clipboard_text() const
{
#if defined(__IOS__)
    return [App::I->ios_view clipboard_get_string];
#elif defined(__OSX__)
    return [App::I->osx_view clipboard_get_string];
#else
    return {};
#endif
}

bool AppleDocumentPlatformServices::set_clipboard_text(std::string_view text) const
{
    const std::string value(text);
#if defined(__IOS__)
    return [App::I->ios_view clipboard_set_string:value];
#elif defined(__OSX__)
    return [App::I->osx_view clipboard_set_string:value];
#else
    (void)value;
    return false;
#endif
}

void AppleDocumentPlatformServices::pick_image(PickedPathCallback callback) const
{
    if (family_ == PlatformFamily::ios)
    {
        if (bridge_.pick_image)
            bridge_.pick_image(std::move(callback));
        return;
    }

    if (family_ == PlatformFamily::macos && bridge_.pick_file)
    {
        bridge_.pick_file(
            apple_image_file_types(),
            [callback = std::move(callback)](std::string path) {
                invoke_picked_path_if_selected(path, callback);
            });
    }
}

void AppleDocumentPlatformServices::pick_file(
    std::vector<std::string> file_types,
    PickedPathCallback callback) const
{
    if (!bridge_.pick_file)
        return;

    if (family_ == PlatformFamily::ios)
    {
        bridge_.pick_file(std::move(file_types), std::move(callback));
        return;
    }

    if (family_ == PlatformFamily::macos)
    {
        bridge_.pick_file(
            std::move(file_types),
            [callback = std::move(callback)](std::string path) {
                invoke_picked_path_if_selected(path, callback);
            });
    }
}

void AppleDocumentPlatformServices::pick_save_file(
    std::vector<std::string> file_types,
    PickedPathCallback callback) const
{
    if (family_ == PlatformFamily::macos && bridge_.pick_save_file)
    {
        bridge_.pick_save_file(
            std::move(file_types),
            [callback = std::move(callback)](std::string path) {
                invoke_picked_path_if_selected(path, callback);
            });
    }
}

void AppleDocumentPlatformServices::pick_directory(PickedPathCallback callback) const
{
    if (family_ == PlatformFamily::macos && bridge_.pick_directory)
    {
        bridge_.pick_directory([callback = std::move(callback)](std::string path) {
            invoke_picked_path_if_selected(path, callback);
        });
    }
}

bool AppleDocumentPlatformServices::supports_working_directory_picker() const
{
    return platform_supports_working_directory_picker(family_);
}

std::string AppleDocumentPlatformServices::format_working_directory_path(std::string_view path) const
{
    if (family_ == PlatformFamily::macos && bridge_.format_working_directory_path)
        return bridge_.format_working_directory_path(path);
    return std::string(path);
}

void AppleDocumentPlatformServices::display_file(std::string_view path) const
{
    const std::string value(path);
#if defined(__IOS__)
    dispatch_async(dispatch_get_main_queue(), ^{
        [App::I->ios_view display_file:value];
    });
#elif defined(__OSX__)
    [[NSWorkspace sharedWorkspace] openFile:[NSString stringWithUTF8String:value.c_str()]];
#else
    (void)value;
#endif
}

void AppleDocumentPlatformServices::share_file(std::string_view path) const
{
    const std::string value(path);
#if defined(__IOS__)
    dispatch_async(dispatch_get_main_queue(), ^{
        [App::I->ios_view share_file:[NSString stringWithUTF8String:value.c_str()]];
    });
#elif defined(__OSX__)
    dispatch_async(dispatch_get_main_queue(), ^{
        [App::I->osx_view share_file:[NSString stringWithUTF8String:value.c_str()]];
    });
#else
    (void)value;
#endif
}

void AppleDocumentPlatformServices::set_cursor_visible(bool visible) const
{
#if defined(__OSX__)
    [App::I->osx_view show_cursor:visible];
#else
    (void)visible;
#endif
}

void AppleDocumentPlatformServices::save_ui_state() const
{
#if defined(__OSX__)
    [App::I->osx_app save_ui_state];
#endif
}

}
