#include <gccore.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <wiiuse/wpad.h>

#include "AnyTitleManager.h"
#include "controller.h"
#include "detect_settings.h"
#include "dopios.h"
#include "fat.h"
#include "id.h"
#include "IOSCheck.h"
#include "IOSPatcher.h"
#include "name.h"
#include "nand.h"
#include "sysconf.h"
#include "SystemMenuMenu.h"
#include "title_install.h"
#include "tools.h"
#include "video.h"
#include "wad.h"

#define ITEMS_PER_PAGE      18
#define MAX_TITLES_RES      (30 * 12)
#define NUM_TYPES           7
#define TITLE_NAME_WIDTH    50
#define MAX_TITLES 256
#define BRICK_PROTECTION 1
const int ITEMS_PER_PAGE_HALF_MIN_ONE = (ITEMS_PER_PAGE / 2) - 1;

s32 uninstallChecked(u32 kind, u32 title) {
    u64 tid = TITLE_ID(kind, title);
    s32 ret;
    u32 i, j;
    for (i = 0; i < 7; i += 1) {
        if (types[i] == kind) {
            break;
        }
    }
    if (i == 7) return -1;
    for (j = 0; j < typeCnt[i]; j += 1) {
        if (installed_titles[i][j].tid == tid) break;
    }
    if (j == typeCnt[i]) {
        printf("COULD NOT FIND TITLE!!!!\n");
        PromptAnyKeyContinue();
        return -1;
    }
    TITLE * curTitle = &installed_titles[i][j];
    bool has_db = !curTitle->failedToReadDB,
            has_bn = !curTitle->failedToReadBN, has_00 =
                    !curTitle->failedToRead00;
    ret = 1;
    u16 system_region = Region_IDs[getRegion()];
    
    initNextBuffer();
    PrintBanner();
    printf("\x1b[2J\n\n");
#ifndef BRICK_PROTECTION
    printf("WARNING!!! BRICK PROTECTION DISABLED!! WARNING!!! BRICK PROTECTION DISABLED!!\n");
#endif
    printf(
        "+- Title -------------------------------------------------------------------+\n");
    if (has_db) printf(" Name DB  : %s\n", curTitle->nameDB);
    if (has_bn) printf(" Name BAN : %s\n", curTitle->nameBN);
    if (has_00) printf(" Name APP : %s\n", curTitle->name00);
    printf(" Title ID : %s (%08x/%08x)\n", curTitle->text, kind, title);
    printf(" IOS req. : %d\n", curTitle->requiredIOS);
    printf(" Version  : %d\n", curTitle->version);
    printf(
        "+---------------------------------------------------------------------------+\n");
    printf(
        "+- Contents ----------------------------------------------------------------+\n");
    printContent(tid);
    printf(
        "+---------------------------------------------------------------------------+\n\n");
    
#ifdef BRICK_PROTECTION
    // Don't uninstall System titles if we can't find sysmenu IOS
    if (kind == 1) {
        if (wiiSettings.sysMenuIOS == 0) {
            printf(
                "\tSafety Check! Can't detect Sysmenu IOS, system title deletes disabled\n");
            printf("\tPlease report this to the author\n");
            flushBuffer();
            PromptAnyKeyContinue();
            return -1;
        }
    }

    // Fail for uninstalls of various titles.
    if (tid == TITLE_ID(1, 0))
        printf("\tBrick protection! You want to delete what?!?\n");
    else if (tid == TITLE_ID(1, 1))
        printf("\tBrick protection! Can't delete boot2!\n");
    else if (tid == TITLE_ID(1, 2))
        printf("\tBrick protection! Can't delete System Menu!\n");
    else if (tid == TITLE_ID(1, wiiSettings.sysMenuIOS))
        printf("\tBrick protection! Can't delete Sysmenu IOS!\n");
    else if (tid == TITLE_ID(1, IOS_GetVersion()))
        printf("\tBrick protection! Can't the currently running IOS!\n");
    else if (tid == TITLE_ID(0x10008, 0x48414B00 | system_region))
        printf("\tBrick protection! Can't delete your region's EULA!\n");
    else if (tid == TITLE_ID(0x10008, 0x48414C00 | system_region))
        printf("\tBrick protection! Can't delete your region's rgnsel!\n");
    else {
#endif

        // Display a warning if you're deleting the Homebrew Channel's IOS
        if (tid == get_title_ios(TITLE_ID(0x10001, 0xAF1BF516))) { //new HBC
            printf(
                "\tWARNING: This is the IOS used by the Homebrew Channel!\n\t- Deleting it will cause the Homebrew Channel to stop working!\n");
        }
        if (tid == get_title_ios(TITLE_ID(0x10001, 0x4A4F4449))) {//HBC
            printf(
                "\tWARNING: This is the IOS used by the Homebrew Channel!\n\t- Deleting it will cause the Homebrew Channel to stop working!\n");
        }
        if (tid == get_title_ios(TITLE_ID(0x10001, 0x48415858))) {//old HBC
            printf(
                "\tWARNING: This is the IOS used by the Homebrew Channel!\n\t- Deleting it will cause the Homebrew Channel to stop working!\n");
        }

        printf("\t               (A) Uninstall this title\n");
        if (has_bn || has_00) printf(
            "\t               (+) Add this title to the database\n");
        printf("\t               (B) Abort\n\n");
        flushBuffer();
        int button;
        button = WaitButtons();
        if (ExitMainThread) return 0;
        if (button & WPAD_BUTTON_HOME) ReturnToLoader();
        
        u32 key;
        if (button & WPAD_BUTTON_B) {
            return 0;
        } else if (button & WPAD_BUTTON_PLUS && (has_bn || has_00)) {
            if (has_db) {
                printf("This title is already present in the database!\n");
                printf(
                    "To add it anyway press (A) or any other button to abort.\n");
                if (!(ScanPads(&key) & WPAD_BUTTON_A)) return 1;
            }
            ret = 1;
            if (has_bn)
                addTitleToDatabase(titleText(kind, title), curTitle->nameBN);
            else
                addTitleToDatabase(titleText(kind, title), curTitle->name00);
        } else if (button & WPAD_BUTTON_A) {
            ret = Uninstall_FromTitle(tid);
        }
#ifdef BRICK_PROTECTION
    }
#endif
    return ret;
}

int manageTitles(int menu_index) {
    static int menuItem = 0;
    u32 button = 0, tlo, thi = types[menu_index];
    u64 tid;
    unsigned int num_titles = typeCnt[menu_index];
    int i, ret = 0, startTitles = 0;
    char name[256], name2[256];
    u8 mode;
    TITLE *curTitle;
    if (menu_index < 0 || menu_index > 6) return -1;
    while (num_titles > 0 && !(button & WPAD_BUTTON_B)) {
        initNextBuffer();
        PrintBanner();

        if (menuItem > num_titles) {
            menuItem = 0;
            startTitles = 0;
        }
        ret = 1;
        mode = getDispMode();
        printf("\tTitles in %08x\t\titem ", thi);
        Console_SetFgColor(GREEN, 0);
        printf("%2d", menuItem + startTitles + 1);
        Console_SetFgColor(WHITE, 0);
        printf(" of %2d\t(%-5s) (%-9s)\n", num_titles, getDispModeName(),
            getNamingMode());
        for (i = 0; i < ITEMS_PER_PAGE; i += 1) {
            curTitle = &installed_titles[menu_index][startTitles + i];
            tlo = TITLE_LOWER(curTitle->tid);
            if ((startTitles + i) >= num_titles) {
                break;
            }
            getTitle_Name(name, curTitle);
            u8 len = strlen(name);
            if (len > TITLE_NAME_WIDTH) {
                len = TITLE_NAME_WIDTH;
            }
            memcpy(name2, name, len);
            name2[len] = '\0';
            if (mode == 0) {
                printf("\t%3s %s\n", (menuItem == i) ? "-->" : " ", name2);
            } else if (mode == 1) {
                printf("\t%3s ", (menuItem == i) ? "-->" : " ");
                Console_SetFgColor(GREEN, 0);
                printf("%s", curTitle->text);
                Console_SetFgColor(WHITE, 0);
                printf(" %s\n", name2);
            } else {

                printf("\t%3s ", (menuItem == i) ? "-->" : " ");
                Console_SetFgColor(GREEN, 0);
                printf("%s", curTitle->text);
                Console_SetFgColor(WHITE, 0);
                printf(" (");
                Console_SetFgColor(CYAN, 0);
                printf("%08x", tlo);
                Console_SetFgColor(WHITE, 0);
                printf(") %s\n", name2);
            }
        }
        Console_SetPosition(ConsoleRows - 5, 0);
        horizontalLineBreak();
        printf(
            "\n\t(%s)/(%s) (%s)/(%s) Change Selection\t(B) Back\t(HOME)/GC:(START) Exit\n",
            UP_ARROW, DOWN_ARROW, LEFT_ARROW, RIGHT_ARROW);
        printf("\t(-)/GC:(L)\tDelete\t\t\t(+)/GC:(R)\tExtract to Wad\n");
        printf(
            "\t(1)/GC:(Y)\tChange Display Mode\t(2)/GC:(Z)\tChange Naming Mode");
        flushBuffer();
        button = WaitButtons();
        if (ExitMainThread) return -1;
        curTitle = &installed_titles[menu_index][startTitles + menuItem];
        tlo = TITLE_LOWER(curTitle->tid);
        tid = TITLE_ID(thi, tlo);
        
        if (button & WPAD_BUTTON_HOME) {
            ReturnToLoader();
        } else if (button & WPAD_BUTTON_UP) {
            if (num_titles < ITEMS_PER_PAGE) {
                if (menuItem > 0 && menuItem < num_titles) {
                    menuItem--;
                } else {
                    menuItem = num_titles - 1;
                }
            } else {
                if (menuItem > ITEMS_PER_PAGE_HALF_MIN_ONE) {
                    menuItem--;
                } else if (startTitles > 0) {
                    startTitles--;
                } else if (menuItem > 0) {
                    menuItem--;
                } else {
                    startTitles = num_titles - ITEMS_PER_PAGE;
                    menuItem = ITEMS_PER_PAGE - 1;
                }
            }
        } else if (button & WPAD_BUTTON_DOWN) {
            if (num_titles < ITEMS_PER_PAGE) {
                if (menuItem >= 0 && menuItem + 1 < num_titles) {
                    menuItem++;
                } else {
                    menuItem = 0;
                }
            } else {
                if (menuItem < ITEMS_PER_PAGE_HALF_MIN_ONE) {
                    menuItem++;
                } else if (startTitles + ITEMS_PER_PAGE < num_titles) {
                    startTitles++;
                } else if (startTitles + menuItem + 1 < num_titles) {
                    menuItem++;
                } else {
                    startTitles = 0;
                    menuItem = 0;
                }
            }
        } else if (button & WPAD_BUTTON_LEFT && num_titles > ITEMS_PER_PAGE) {
            if (startTitles + menuItem <= ITEMS_PER_PAGE_HALF_MIN_ONE) {
                startTitles = 0;
                menuItem = 0;
            } else if (menuItem >= ITEMS_PER_PAGE_HALF_MIN_ONE) {
                menuItem -= ITEMS_PER_PAGE_HALF_MIN_ONE;
            } else if (startTitles <= ITEMS_PER_PAGE) {
                startTitles = 0;
                menuItem = ITEMS_PER_PAGE - 1;
            } else {
                startTitles -= ITEMS_PER_PAGE - 1;
                menuItem = ITEMS_PER_PAGE - 1;
            }
        } else if (button & WPAD_BUTTON_RIGHT && num_titles > ITEMS_PER_PAGE) {
            if (startTitles + menuItem + ITEMS_PER_PAGE_HALF_MIN_ONE
                    >= num_titles) {
                startTitles = num_titles - ITEMS_PER_PAGE;
                menuItem = ITEMS_PER_PAGE - 1;
            } else if (menuItem + ITEMS_PER_PAGE_HALF_MIN_ONE < ITEMS_PER_PAGE) {
                menuItem += ITEMS_PER_PAGE_HALF_MIN_ONE;
            } else if (startTitles + menuItem + ITEMS_PER_PAGE >= num_titles) {
                startTitles = num_titles - ITEMS_PER_PAGE;
                menuItem = ITEMS_PER_PAGE - 1;
            } else {
                startTitles += ITEMS_PER_PAGE - 1;
                menuItem = 0;
            }
        } else if (button & WPAD_BUTTON_1) {
            changeDispMode();
        } else if (button & WPAD_BUTTON_2) {
            changeNamingMode();
        } else if (button & WPAD_BUTTON_PLUS) {
            PrintBanner();
            char testid[256];
            ret = Fat_Mount(&fdevList[0]);
            if (ret < 0) {
                continue;
            }
            snprintf(testid, sizeof(testid), "sd:/WAD/wiimod/%08x-%08x.wad",
                thi, tlo);
            Wad_Dump(tid, testid);
            Fat_Unmount(&fdevList[0]);
            PromptAnyKeyContinue();
        } else if (button & WPAD_BUTTON_MINUS) {
            PrintBanner();
            printf("\nAre you sure you want to delete/title/%08x/%08x?\n\n",
                thi, tlo);
            if (PromptContinue()) {
                ret = uninstallChecked(thi, tlo);
                if (ret == 0) {
                    updateTitles();
                    num_titles = typeCnt[menu_index];
                }
            }
        }
    }
    return ret;
}

void anyTitleManagerMenu() {
    // The name of the database file
    static int menuItem = 0;
    u32 button = 0;
    int ret;

    PrintBanner();

    if (wiiSettings.reRunWithSU) {
        updateTitles();
    }
    /*else {
        ret = Identify_SU();
        if (ret < 0) {
            printf("Unexpected Error: %s Value: %d\n", "Identify_SU", ret);
            PromptAnyKeyContinue();
            return;
        }
    }*/

    while (!(button & WPAD_BUTTON_B)) {
        initNextBuffer();
        PrintBanner();
        printf("\n\n\n\t\t\t\t%3s 00000001 - System Titles\n", (menuItem == 0)
            ? "-->" : " ");
        printf("\t\t\t\t%3s 00010000 - Disc Game Titles (and saves)\n",
            (menuItem == 1) ? "-->" : " ");
        printf("\t\t\t\t%3s 00010001 - Installed Channel Titles\n", (menuItem
                == 2) ? "-->" : " ");
        printf("\t\t\t\t%3s 00010002 - System Channel Titles\n",
            (menuItem == 3) ? "-->" : " ");
        printf(
            "\t\t\t\t%3s 00010004 - Games that use Channels (Channel+Save)\n",
            (menuItem == 4) ? "-->" : " ");
        printf("\t\t\t\t%3s 00010005 - Downloadable Game Content\n", (menuItem
                == 5) ? "-->" : " ");
        printf("\t\t\t\t%3s 00010008 - Hidden Channels\n", (menuItem == 6)
            ? "-->" : " ");
        Console_SetPosition(ConsoleRows - 5, 0);
        horizontalLineBreak();
        printf("\n\t(%s)/(%s)\t\tChange Selection\n", UP_ARROW, DOWN_ARROW);
        printf("\t(A)\t\t\t\t\tSelect\t\t\t\t\t(B)\tBack\n");
        printf("\t(HOME)/GC:(START)\t\tExit");
        flushBuffer();
        
        button = WaitButtons();
        if (ExitMainThread) break;
        if (button & WPAD_BUTTON_HOME) ReturnToLoader();
        if (button & WPAD_BUTTON_A) {
            Nand_Init();
            ret = manageTitles(menuItem);
            ISFS_Deinitialize();
            if (ret < 1) {
                PromptAnyKeyContinue();
            }
        }

        if (button & WPAD_BUTTON_DOWN) menuItem++;
        if (button & WPAD_BUTTON_UP) menuItem--;
        
        if (menuItem > 6) menuItem = 0;
        if (menuItem < 0) menuItem = 6;
    }
}
