#include "common.h"
#include "effects_internal.h"
#include "message_ids.h"

typedef struct {
    /* 0x00 */ Gfx* displayList;
    /* 0x04 */ s16 x;
    /* 0x06 */ s16 y;
    /* 0x08 */ s16 width;
    /* 0x0A */ s16 height;
} UnkStruct; // size: 0xC

extern Gfx D_0900BE40_3F7CA0[];
extern Gfx D_0900BE88_3F7CE8[];
extern Gfx D_0900BED0_3F7D30[];
extern Gfx D_0900BF18_3F7D78[];
extern Gfx D_0900BF60_3F7DC0[];
extern Gfx D_0900BFA8_3F7E08[];
extern Gfx D_0900BFF0_3F7E50[];
extern Gfx D_0900C038_3F7E98[];
extern Gfx D_0900C080_3F7EE0[];
extern Gfx D_0900C168_3F7FC8[];
extern Gfx D_0900C1B0_3F8010[];
extern Gfx D_0900C1F8_3F8058[];
extern Gfx D_0900C240_3F80A0[];
extern Gfx D_0900C328_3F8188[];
extern Gfx D_0900C370_3F81D0[];
extern Gfx D_0900C458_3F82B8[];
extern Gfx D_0900C540_3F83A0[];

s32 D_E010E750[] = {
    -1,
    MSG_Menus_019D, MSG_Menus_019E, MSG_Menus_019F,
    MSG_Menus_01A0, MSG_Menus_01A1, MSG_Menus_01A2,
    MSG_Menus_01A3, MSG_Menus_01A4, MSG_Menus_019C,
    -1, -1, -1, -1, -1, -1, -1, -1, -1
};

UnkStruct D_E010E79C[] = {
    { D_0900C080_3F7EE0, 104,  0, 128, 10 },
    { D_0900C168_3F7FC8, 104, 10, 128, 10 },
    { D_0900C1B0_3F8010, 104, 20, 128, 10 },
    { D_0900C1F8_3F8058, 104, 30, 128, 10 },
    {              NULL,   0,  0,   0,  0 }
};

UnkStruct D_E010E7D8[] = {
    { D_0900C458_3F82B8, -16, -6, 144, 20 },
    { D_0900C540_3F83A0, -16, 14, 144, 20 },
    {              NULL,   0,  0,   0,  0 }
};

UnkStruct D_E010E7FC[] = {
    { D_0900C080_3F7EE0, 0, -6, 128, 10 },
    { D_0900C168_3F7FC8, 0,  4, 128, 10 },
    { D_0900C1B0_3F8010, 0, 14, 128, 10 },
    { D_0900C1F8_3F8058, 0, 24, 128, 10 },
    {              NULL, 0,  0,   0,  0 }
};

UnkStruct D_E010E838[] = {
    { D_0900C240_3F80A0,   0,  0, 104, 20 },
    { D_0900C328_3F8188,   0, 20, 104, 20 },
    { D_0900C370_3F81D0, 232,  0,  16, 40 },
    {              NULL,   0,  0,   0,  0 }
};

UnkStruct D_E010E868[] = {
    { D_0900BE40_3F7CA0, 128, -33, 64, 64 },
    {              NULL,   0,   0,  0,  0 },
    { D_0900BE88_3F7CE8, 128, -33, 64, 64 },
    {              NULL,   0,   0,  0,  0 },
    { D_0900BED0_3F7D30, 128, -33, 64, 64 },
    {              NULL,   0,   0,  0,  0 },
    { D_0900BF18_3F7D78, 128, -33, 64, 64 },
    {              NULL,   0,   0,  0,  0 },
    { D_0900BF60_3F7DC0, 128, -33, 64, 64 },
    {              NULL,   0,   0,  0,  0 },
    { D_0900BFA8_3F7E08, 128, -33, 64, 64 },
    {              NULL,   0,   0,  0,  0 },
    { D_0900BFF0_3F7E50, 128, -33, 64, 64 },
    {              NULL,   0,   0,  0,  0 },
    { D_0900C038_3F7E98, 128, -33, 64, 64 },
    {              NULL,   0,   0,  0,  0 }
};

void chapter_change_init(EffectInstance* effect);
void chapter_change_update(EffectInstance* effect);
void chapter_change_render(EffectInstance* effect);
void chapter_change_appendGfx(void* effect);
void shim_draw_msg(s32, s32, s32, s32, s32, s32);
s32 shim_get_msg_width(s32, u16);

void func_E010E000(ChapterChangeFXData* data, s32 arg1, UnkStruct* arg2) {
    s32 unk_1C = data->lifetime;
    UnkStruct* it;
    f32 posX;
    f32 posY;
    s32 temp;

    if (arg1 == 0) {
        posX = data->chapterPos.x;
        posY = data->chapterPos.y;
    } else {
        posX = data->endOfPos.x;
        posY = data->endOfPos.y;
    }

    if (arg2 != NULL) {
        for (it = arg2; it->displayList != NULL; it++) {
            gSPDisplayList(gMainGfxPos++, it->displayList);

            temp = it->x - 384;
            gDPSetTileSize(gMainGfxPos++, 1, (unk_1C * 4 - temp) * 4, 0, (unk_1C * 4 - it->x + 511) * 4, 0);
            gSPScisTextureRectangle(gMainGfxPos++,
                (posX + it->x) * 4,
                (posY + it->y) * 4,
                (posX + it->x + it->width) * 4,
                (posY + it->y + it->height) * 4,
                G_TX_RENDERTILE, 0, 0, 1024, 1024);
        }

        gDPPipeSync(gMainGfxPos++);
    }
}

EffectInstance* chapter_change_main(s32 arg0, f32 posX, f32 posY, f32 arg3, f32 arg4, s32 duration) {
    EffectBlueprint bp;
    ChapterChangeFXData* data;
    EffectInstance* effect;
    s32 numParts = 1;

    bp.init = chapter_change_init;
    bp.update = chapter_change_update;
    bp.renderWorld = chapter_change_render;
    bp.unk_00 = 0;
    bp.unk_14 = NULL;
    bp.effectID = EFFECT_CHAPTER_CHANGE;

    effect = shim_create_effect_instance(&bp);
    effect->numParts = numParts;
    data = effect->data.chapterChange = shim_general_heap_malloc(numParts * sizeof(*data));
    ASSERT(effect->data.chapterChange != NULL);

    data->unk_00 = arg0;
    data->lifetime = 0;
    if (duration <= 0) {
        data->timeLeft = 1000;
    } else {
        data->timeLeft = duration;
    }
    data->chapterPos.x = data->endOfPos.x = posX;
    data->chapterPos.y = data->endOfPos.y = posY;
    data->unk_0C = arg3;
    data->unk_50 = arg4;
    data->unk_20 = 255;
    data->unk_24 = 255;
    data->unk_28 = 255;
    data->unk_2C = 255;
    data->unk_30 = 0;
    data->unk_34 = 0;
    data->unk_38 = 0;
    if (arg0 == 0 || (arg0 >= 10 && arg0 <= 18)) {
        data->unk_3C = 0;
    } else {
        data->unk_3C = 255;
    }
    data->unk_54 = D_E010E750[arg0];
    if (data->unk_54 >= 0) {
        data->unk_40 = 160;
        data->unk_44 = 160;
        data->unk_48 = shim_get_msg_width(data->unk_54, 0);
        data->unk_4C = 24;
    }

    return effect;
}

void chapter_change_init(EffectInstance* effect) {
}

void chapter_change_update(EffectInstance* effect) {
    ChapterChangeFXData* data = effect->data.chapterChange;

    if (effect->flags & EFFECT_INSTANCE_FLAG_10) {
        effect->flags &= ~EFFECT_INSTANCE_FLAG_10;
        data->timeLeft = 16;
    }

    if (data->timeLeft < 1000) {
        data->timeLeft--;
    }

    data->lifetime++;

    if (data->timeLeft < 0) {
        shim_remove_effect(effect);
    }
}

void chapter_change_render(EffectInstance* effect) {
    RenderTask renderTask;
    RenderTask* retTask;

    renderTask.appendGfx = chapter_change_appendGfx;
    renderTask.appendGfxArg = effect;
    renderTask.distance = 10;
    renderTask.renderMode = RENDER_MODE_2D;

    retTask = shim_queue_render_task(&renderTask);
    retTask->renderMode |= RENDER_TASK_FLAG_REFLECT_FLOOR;
}

void chapter_change_appendGfx(void* effect) {
    ChapterChangeFXData* data = ((EffectInstance*)effect)->data.chapterChange;
    s32 unk_2C = data->unk_2C;
    u32 unk_00 = data->unk_00;
    UnkStruct* ptr0;
    UnkStruct* ptr1;

    gDPPipeSync(gMainGfxPos++);
    gSPSegment(gMainGfxPos++, 0x09, VIRTUAL_TO_PHYSICAL(((EffectInstance*)effect)->graphics->data));

    switch (unk_00) {
        case 1:
        case 2:
        case 3:
        case 4:
        case 5:
        case 6:
        case 7:
        case 8:
            ptr0 = D_E010E7FC;
            ptr1 = &D_E010E868[(unk_00 - 1) * 2];
            break;
        case 9:
            ptr0 = D_E010E7D8;
            ptr1 = NULL;
            break;
        case 0:
        case 10:
        case 11:
        case 12:
        case 13:
        case 14:
        case 15:
        case 16:
        case 17:
        case 18:
            ptr0 = D_E010E79C;
            ptr1 = D_E010E838;
            break;
        default:
            ptr1 = NULL;
            ptr0 = NULL;
            break;
    }

    gDPSetPrimColor(gMainGfxPos++, 0, 0, data->unk_20, data->unk_24, data->unk_28, unk_2C);
    gDPSetEnvColor(gMainGfxPos++, data->unk_30, data->unk_34, data->unk_38, data->unk_3C);

    func_E010E000(data, 0, ptr0);
    func_E010E000(data, 1, ptr1);

    if (data->unk_54 >= 0) {
        shim_draw_msg(data->unk_54, data->unk_40 - data->unk_48, data->unk_44, 255, 21, 0);
    }

    gDPPipeSync(gMainGfxPos++);
}
