/*
 * Copyright (c) Souldbminer, Lightos_ and Horizon OC Contributors
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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, see <http://www.gnu.org/licenses/>.
 */

#pragma once
#include "../../ipc.h"

#include <atomic>
#include <string>

#include "base_menu_gui.h"

class UpdateStatusPanel;

class UpdateGui : public BaseMenuGui {

public:
    UpdateGui();
    ~UpdateGui();

    void listUI() override;
    void update() override;
    bool handleInput(u64 keysDown, u64 keysHeld, const HidTouchState &touchPos,
                     HidAnalogStickState leftJoy, HidAnalogStickState rightJoy) override;

private:
    enum class UpdateStage {
        Idle,
        Downloading,
        Extracting,
        Done,
        Failed,
        Cancelled,
    };

    struct PackageInfo {
        const char *displayName;
        const char *url;
        const char *zipPath;
    };

    static constexpr PackageInfo kPackages[2] = {
        {"Horizon OC",     "https://github.com/Horizon-OC/Horizon-OC/releases/latest/download/dist.zip", "sdmc:/config/horizon-oc/dist.zip"},
        {"Horizon OC + Extensions", "https://github.com/Horizon-OC/Horizon-OC/releases/latest/download/dist_ext.zip", "sdmc:/config/horizon-oc/dist_ext.zip"},
    };

    bool isBusy() const {
        return m_stage.load(std::memory_order_acquire) != UpdateStage::Idle;
    }

    void startJob(int packageIndex, bool extractOnly);
    void requestCancel();
    void reapThread();
    void pollJob();

    static void jobEntry(void *arg);
    void jobBody();

    std::atomic<UpdateStage> m_stage{UpdateStage::Idle};
    int m_activePackage = -1;
    bool m_extractOnly = false;
    bool m_threadActive = false;
    Thread m_thread{};
    std::string m_resultMessage;

    tsl::elm::ListItem *m_items[2] = {nullptr, nullptr};
    UpdateStatusPanel *m_status = nullptr;

protected:
    std::string getJumpToItemName() override;
};
