// Vita3K emulator project
// Copyright (C) 2026 Vita3K team
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.

#include "private.h"

#include <config/functions.h>
#include <config/state.h>
#include <dialog/state.h>
#include <gui/functions.h>
#include <host/dialog/filesystem.h>
#include <lang/functions.h>

#ifdef __ANDROID__
#include <SDL3/SDL_system.h>
#include <jni.h>
#endif

namespace gui {

void get_firmware_file(EmuEnvState &emuenv) {
    const std::map<int, std::string> locale_id = {
        { SCE_SYSTEM_PARAM_LANG_JAPANESE, "ja-jp" },
        { SCE_SYSTEM_PARAM_LANG_ENGLISH_US, "en-us" },
        { SCE_SYSTEM_PARAM_LANG_FRENCH, "fr-fr" },
        { SCE_SYSTEM_PARAM_LANG_SPANISH, "es-es" },
        { SCE_SYSTEM_PARAM_LANG_GERMAN, "de-de" },
        { SCE_SYSTEM_PARAM_LANG_ITALIAN, "it-it" },
        { SCE_SYSTEM_PARAM_LANG_DUTCH, "nl-nl" },
        { SCE_SYSTEM_PARAM_LANG_PORTUGUESE_PT, "pt-pt" },
        { SCE_SYSTEM_PARAM_LANG_RUSSIAN, "ru-ru" },
        { SCE_SYSTEM_PARAM_LANG_KOREAN, "ko-kr" },
        { SCE_SYSTEM_PARAM_LANG_CHINESE_T, "zh-hant-hk" },
        { SCE_SYSTEM_PARAM_LANG_CHINESE_S, "zh-hans-cn" },
        { SCE_SYSTEM_PARAM_LANG_FINNISH, "fi-fi" },
        { SCE_SYSTEM_PARAM_LANG_SWEDISH, "sv-se" },
        { SCE_SYSTEM_PARAM_LANG_DANISH, "da-dk" },
        { SCE_SYSTEM_PARAM_LANG_NORWEGIAN, "no-no" },
        { SCE_SYSTEM_PARAM_LANG_POLISH, "pl-pl" },
        { SCE_SYSTEM_PARAM_LANG_PORTUGUESE_BR, "pt-br" },
        { SCE_SYSTEM_PARAM_LANG_ENGLISH_GB, "en-gb" },
        { SCE_SYSTEM_PARAM_LANG_TURKISH, "tr-tr" },
    };
    const auto &locale = locale_id.at(emuenv.cfg.sys_lang);
    open_path(fmt::format("https://www.playstation.com/{}/support/hardware/psvita/system-software", locale));
}

void draw_initial_setup(GuiState &gui, EmuEnvState &emuenv) {
    enum InitialSetup {
        SELECT_LANGUAGE,
        SELECT_PREF_PATH,
        INSTALL_FIRMWARE,
        SELECT_INTERFACE_SETTINGS,
        FINISHED
    };

#ifdef __ANDROID__
    static bool has_all_files_access = false;
#endif
    static InitialSetup setup = SELECT_LANGUAGE;
    static std::string title_str;

    const ImVec2 VIEWPORT_SIZE(emuenv.logical_viewport_size.x, emuenv.logical_viewport_size.y);
    const ImVec2 VIEWPORT_POS(emuenv.logical_viewport_pos.x, emuenv.logical_viewport_pos.y);
    const ImVec2 RES_SCALE(emuenv.gui_scale.x, emuenv.gui_scale.y);
    const auto SCALE = ImVec2(RES_SCALE.x * emuenv.manual_dpi_scale, RES_SCALE.y * emuenv.manual_dpi_scale);
    const ImVec2 WINDOW_SIZE(756.f * SCALE.x, 418.f * SCALE.y);
    const auto SELECT_SIZE(72.f * SCALE.y);
    const ImVec2 BUTTON_SIZE(186.f * SCALE.x, 52.f * SCALE.y);
    const ImVec2 BUTTON_POS(8.f * SCALE.x, VIEWPORT_SIZE.y - BUTTON_SIZE.y - (6.f * SCALE.y));
    const ImVec2 BIG_BUTTON_SIZE(364.f * SCALE.x, 48.f * SCALE.y);
    const ImVec2 BIG_BUTTON_POS((WINDOW_SIZE.x / 2.f) - (BIG_BUTTON_SIZE.x / 2.f), WINDOW_SIZE.y - BIG_BUTTON_SIZE.y - (20.f * SCALE.y));

    auto &lang = gui.lang.initial_setup;
    auto &common = emuenv.common_dialog.lang.common;
    auto &welcome = gui.lang.welcome;

    const auto is_default_path = emuenv.cfg.pref_path == emuenv.default_path;
    const auto FW_PREINST_PATH{ emuenv.pref_path / "pd0" };
    const auto FW_PREINST_INSTALLED = fs::exists(FW_PREINST_PATH) && !fs::is_empty(FW_PREINST_PATH);
    const auto FW_PATH{ emuenv.pref_path / "vs0" };
    const auto FW_INSTALLED = fs::exists(FW_PATH) && !fs::is_empty(FW_PATH);
    const auto FW_FONT_PATH{ emuenv.pref_path / "sa0" };
    const auto FW_FONT_INSTALLED = fs::exists(FW_FONT_PATH) && !fs::is_empty(FW_FONT_PATH);

    ImGui::PushFont(gui.vita_font[emuenv.current_font_level]);
    ImGui::SetNextWindowPos(VIEWPORT_POS, ImGuiCond_Always);
    ImGui::SetNextWindowSize(VIEWPORT_SIZE, ImGuiCond_Always);
    ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.f);
    ImGui::PushStyleVar(ImGuiStyleVar_WindowBorderSize, 0.f);
    ImGui::Begin("##initial_setup", &emuenv.cfg.initial_setup, ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings);
    ImGui::PopStyleVar(2);

    ImGui::GetBackgroundDrawList()->AddRectFilled(VIEWPORT_POS, ImVec2(VIEWPORT_POS.x + VIEWPORT_SIZE.x, VIEWPORT_POS.y + VIEWPORT_SIZE.y), IM_COL32(194.f, 207.f, 241.f, 255.f), 0.f, ImDrawFlags_RoundCornersAll);
    ImGui::SetNextWindowPos(ImVec2(VIEWPORT_POS.x + (98.f * SCALE.x), VIEWPORT_POS.y + (30 * SCALE.y)), ImGuiCond_Always);
    ImGui::PushStyleVar(ImGuiStyleVar_FrameRounding, 12.f * SCALE.x);
    ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 6.f * SCALE.x);
    ImGui::PushStyleVar(ImGuiStyleVar_ChildBorderSize, 2.f * SCALE.x);
    ImGui::PushStyleColor(ImGuiCol_Border, GUI_COLOR_TEXT);
    ImGui::SetNextWindowBgAlpha(0.0f);

    ImGui::BeginChild("##window_box", WINDOW_SIZE, ImGuiChildFlags_Borders, ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoSavedSettings);
    ImGui::SetWindowFontScale(1.6f * RES_SCALE.x);
    const auto SELECT_COLOR = ImVec4(0.23f, 0.68f, 0.95f, 0.60f);
    const auto SELECT_COLOR_HOVERED = ImVec4(0.23f, 0.68f, 0.99f, 0.80f);
    const auto SELECT_COLOR_ACTIVE = ImVec4(0.23f, 0.68f, 1.f, 1.f);

    ImGui::SetCursorPosY((47 * SCALE.y) - (ImGui::GetFontSize() / 2.f));
    TextCentered(title_str.c_str());
    ImGui::SetWindowFontScale(1.4f * RES_SCALE.x);
    ImGui::SetCursorPosY(94.f * SCALE.y);
    ImGui::Separator();
    switch (setup) {
    case SELECT_LANGUAGE:
        title_str = lang["select_language"];
        ImGui::SetNextWindowPos(ImVec2(VIEWPORT_POS.x + (198.f * SCALE.x), VIEWPORT_POS.y + (126.f * SCALE.y)), ImGuiCond_Always);
        ImGui::BeginChild("##lang_list", ImVec2(WINDOW_SIZE.x - (200.f * SCALE.x), WINDOW_SIZE.y - (108.f * SCALE.y)), ImGuiChildFlags_None, ImGuiWindowFlags_NoBackground | ImGuiWindowFlags_NoSavedSettings);
        ImGui::Columns(3, nullptr, false);
        ImGui::SetColumnWidth(0, 90.f * SCALE.x);
        ImGui::SetColumnWidth(1, 34.f * SCALE.x);
        ImGui::PushStyleVar(ImGuiStyleVar_SelectableTextAlign, ImVec2(0.f, 0.5f));
        ImGui::PushStyleColor(ImGuiCol_Header, SELECT_COLOR);
        ImGui::PushStyleColor(ImGuiCol_HeaderHovered, SELECT_COLOR_HOVERED);
        ImGui::PushStyleColor(ImGuiCol_HeaderActive, SELECT_COLOR_ACTIVE);
        for (const auto &sys_lang : LIST_SYS_LANG) {
            ImGui::PushID(sys_lang.first);
            // Empty Padding
            ImGui::NextColumn();
            const auto is_current_lang = emuenv.cfg.sys_lang == sys_lang.first;
            if (ImGui::Selectable(is_current_lang ? "V" : "##lang_list", false, ImGuiSelectableFlags_SpanAllColumns, ImVec2(WINDOW_SIZE.x, SELECT_SIZE))) {
                emuenv.cfg.sys_lang = sys_lang.first;
                lang::init_lang(gui.lang, emuenv);
            }
            ImGui::NextColumn();
            ImGui::Selectable(sys_lang.second.c_str(), false, ImGuiSelectableFlags_None, ImVec2(WINDOW_SIZE.x, SELECT_SIZE));
            ImGui::Separator();
            ImGui::NextColumn();
            ImGui::PopID();
        }
        ImGui::PopStyleVar();
        ImGui::PopStyleColor(3);
        ImGui::Columns(1);
        ImGui::ScrollWhenDragging();
        ImGui::EndChild();
        break;

    case SELECT_PREF_PATH:
        title_str = lang["select_pref_path"];
        ImGui::SetCursorPosY((WINDOW_SIZE.y / 2.f) - ImGui::GetFontSize());
#ifdef __ANDROID__
        has_all_files_access = []() -> bool {
            JNIEnv *env = reinterpret_cast<JNIEnv *>(SDL_GetAndroidJNIEnv());
            jobject activity = reinterpret_cast<jobject>(SDL_GetAndroidActivity());
            jclass clazz = env->GetObjectClass(activity);

            jmethodID method_id = env->GetMethodID(clazz, "isStorageManagerEnabled", "()Z");
            jboolean result = env->CallBooleanMethod(activity, method_id);

            env->DeleteLocalRef(clazz);
            env->DeleteLocalRef(activity);

            return result == JNI_TRUE;
        }();

        if (!has_all_files_access) {
            TextColoredCentered(ImVec4(0.98f, 0.01f, 0.20f, 1.0f), lang["storage_file_permissions"].c_str(), 20.f * SCALE.x);
            ImGui::SetCursorPos(BIG_BUTTON_POS);
            if (ImGui::Button(lang["grant_access"].c_str(), BIG_BUTTON_SIZE)) {
                JNIEnv *env = reinterpret_cast<JNIEnv *>(SDL_GetAndroidJNIEnv());
                jobject activity = reinterpret_cast<jobject>(SDL_GetAndroidActivity());
                jclass clazz(env->GetObjectClass(activity));
                jmethodID method_id = env->GetMethodID(clazz, "setStoragePermission", "()V");
                env->CallVoidMethod(activity, method_id);
                env->DeleteLocalRef(activity);
                env->DeleteLocalRef(clazz);
            }
            break;
        }
#endif
        TextColoredCentered(GUI_COLOR_TEXT_TITLE, lang["current_emu_path"].c_str());
        ImGui::Spacing();
        TextCentered(emuenv.cfg.pref_path.c_str(), 0);
        ImGui::SetCursorPos(!is_default_path ? ImVec2((WINDOW_SIZE.x / 2.f) - BIG_BUTTON_SIZE.x - (20.f * SCALE.x), BIG_BUTTON_POS.y) : BIG_BUTTON_POS);
        if (ImGui::Button(lang["change_emu_path"].c_str(), BIG_BUTTON_SIZE)) {
            fs::path emulator_path{};
            host::dialog::filesystem::Result result = host::dialog::filesystem::pick_folder(emulator_path);

            if ((result == host::dialog::filesystem::Result::SUCCESS) && (emulator_path.native() != emuenv.pref_path.native())) {
                emuenv.pref_path = fs::path(emulator_path.native()) / "";
                emuenv.cfg.set_pref_path(emuenv.pref_path);
            } else if (result == host::dialog::filesystem::Result::ERROR) {
                LOG_CRITICAL("Error initializing file dialog: {}", host::dialog::filesystem::get_error());
            }
        }
        if (!is_default_path) {
            ImGui::SameLine(0, 40.f * SCALE.x);
            if (ImGui::Button(lang["reset_emu_path"].c_str(), BIG_BUTTON_SIZE)) {
                if (emuenv.default_path != emuenv.pref_path) {
                    emuenv.pref_path = emuenv.default_path;
                    emuenv.cfg.set_pref_path(emuenv.default_path);
                }
            }
        }
        break;

    case INSTALL_FIRMWARE:
        title_str = lang["install_firmware"];
        ImGui::SetCursorPosY((WINDOW_SIZE.y / 2.f) - (ImGui::GetFontSize() * 3.5f));
        TextColoredCentered(GUI_COLOR_TEXT_TITLE, lang["install_highly_recommended"].c_str());
        ImGui::Spacing();
        if (ImGui::Button(welcome["download_preinst_firmware"].c_str(), BIG_BUTTON_SIZE))
            open_path("https://bit.ly/4hlePsX");
        ImGui::SameLine(0, 20.f * SCALE.x);
        ImGui::Text("%s %s", lang["installed"].c_str(), FW_PREINST_INSTALLED ? "V" : "X");
        ImGui::Spacing();
        if (ImGui::Button(welcome["download_firmware"].c_str(), BIG_BUTTON_SIZE))
            get_firmware_file(emuenv);
        ImGui::SameLine(0, 20.f * SCALE.x);
        ImGui::Text("%s %s", lang["installed"].c_str(), FW_INSTALLED ? "V" : "X");
        ImGui::Spacing();
        if (ImGui::Button(lang["download_font_package"].c_str(), BIG_BUTTON_SIZE))
            open_path("https://bit.ly/48ouDaa");
        ImGui::SameLine(0, 20.f * SCALE.x);
        ImGui::Text("%s %s", lang["installed"].c_str(), FW_FONT_INSTALLED ? "V" : "X");
        ImGui::SetCursorPos(BIG_BUTTON_POS);
        if (ImGui::Button(lang["install_firmware_file"].c_str(), BIG_BUTTON_SIZE))
            gui.file_menu.firmware_install_dialog = true;
        if (gui.file_menu.firmware_install_dialog) {
            ImGui::SetWindowFontScale(RES_SCALE.y);
            draw_firmware_install_dialog(gui, emuenv);
        }
        break;

    case SELECT_INTERFACE_SETTINGS:
        title_str = lang["select_interface_settings"];
        ImGui::SetCursorPosY((WINDOW_SIZE.y / 2.f) - (ImGui::GetFontSize() * 3.f));
        ImGui::Checkbox(gui.lang.settings_dialog.gui["display_info_message"].c_str(), &emuenv.cfg.display_info_message);
        SetTooltipEx(gui.lang.settings_dialog.gui["display_info_message_description"].c_str());
        ImGui::SameLine();
        ImGui::Checkbox(gui.lang.settings_dialog.gui["display_system_apps"].c_str(), &emuenv.cfg.display_system_apps);
        SetTooltipEx(gui.lang.settings_dialog.gui["display_system_apps_description"].c_str());
        ImGui::Spacing();
        ImGui::Checkbox(lang["show_info_bar"].c_str(), &emuenv.cfg.show_info_bar);
        SetTooltipEx(lang["info_bar_description"].c_str());
        ImGui::SameLine();
        ImGui::Checkbox(lang["show_live_area_screen"].c_str(), &emuenv.cfg.show_live_area_screen);
        SetTooltipEx(lang["live_area_screen_description"].c_str());
        ImGui::Spacing();
        ImGui::Checkbox(lang["apps_list_grid"].c_str(), &emuenv.cfg.apps_list_grid);
        SetTooltipEx(lang["apps_list_grid_description"].c_str());
        if (!emuenv.cfg.apps_list_grid) {
            ImGui::Spacing();
            ImGui::SliderInt(lang["icon_size"].c_str(), &emuenv.cfg.icon_size, 64, 128);
            SetTooltipEx(lang["select_icon_size"].c_str());
        }
        ImGui::Spacing();
        if (ImGui::Checkbox(gui.lang.settings.sound_display["system_music"].c_str(), &emuenv.cfg.system_music.value()))
            switch_bgm_state(!emuenv.cfg.system_music.value());
        SetTooltipEx("This option can be changed later in the system Settings app.");
        if (emuenv.cfg.system_music.value()) {
            ImGui::Spacing();
            if (ImGui::SliderInt(gui.lang.settings_dialog.audio["bgm_volume"].c_str(), &emuenv.cfg.bgm_volume, 0, 100, "%d %%", ImGuiSliderFlags_AlwaysClamp))
                set_bgm_volume(emuenv.cfg.bgm_volume);
            SetTooltipEx(gui.lang.settings_dialog.audio["bgm_volume_description"].c_str());
        }
        break;

    case FINISHED:
        title_str = lang["completed"];
        ImGui::SetCursorPosY((WINDOW_SIZE.y / 2.f) - ImGui::GetFontSize());
        TextCentered(lang["completed_setup"].c_str());
        ImGui::SetCursorPos(BIG_BUTTON_POS);
        if (ImGui::Button(common["ok"].c_str(), BIG_BUTTON_SIZE) || ImGui::IsKeyPressed(static_cast<ImGuiKey>(emuenv.cfg.keyboard_button_cross))) {
            emuenv.cfg.initial_setup = true;
            stop_bgm();
            config::serialize_config(emuenv.cfg, emuenv.config_path);
        }
        break;
    default:
        LOG_ERROR("Unknown initial setup step: {}", static_cast<int>(setup));
        break;
    }

    ImGui::SetWindowFontScale(1.f);
    ImGui::EndChild();
    ImGui::PopStyleVar(2);
    ImGui::PopStyleColor();
    ImGui::SetWindowFontScale(1.5f * RES_SCALE.x);

    // Draw Button
    ImGui::SetCursorPos(BUTTON_POS);
    if ((setup > SELECT_LANGUAGE) && ImGui::Button(lang["back"].c_str(), BUTTON_SIZE) || (setup > SELECT_LANGUAGE) && ImGui::IsKeyPressed(static_cast<ImGuiKey>(emuenv.cfg.keyboard_button_circle)))
        setup = (InitialSetup)(setup - 1);
    ImGui::SetCursorPos(ImVec2(VIEWPORT_SIZE.x - BUTTON_SIZE.x - BUTTON_POS.x, BUTTON_POS.y));
#ifdef __ANDROID__
    ImGui::BeginDisabled((setup == SELECT_PREF_PATH) && !has_all_files_access);
#endif
    if ((setup < FINISHED) && (ImGui::Button(lang["next"].c_str(), BUTTON_SIZE) || ImGui::IsKeyPressed(static_cast<ImGuiKey>(emuenv.cfg.keyboard_button_cross)))) {
        setup = (InitialSetup)(setup + 1);
        config::serialize_config(emuenv.cfg, emuenv.config_path);
    }
#ifdef __ANDROID__
    ImGui::EndDisabled();
#endif
    ImGui::SetWindowFontScale(1.f);

    ImGui::PopStyleVar();
    ImGui::End();
    ImGui::PopFont();
}

} // namespace gui
