#include <assert.h>
#include <stdbool.h>
#include "device/device.h"
#include "game.h"

#define GAME_DIALOGUE_MAX_N_CHARS 256

typedef enum {
    GAME_DIALOGUE_SCREEN_STATE_BOB_IN,
    GAME_DIALOGUE_SCREEN_STATE_TYPEWRITER,
    GAME_DIALOGUE_SCREEN_STATE_WAIT,
    GAME_DIALOGUE_SCREEN_STATE_BOB_OUT,
} game_dialogue_screen_state;

struct {
    bool visible;
    const char* dialogue;

    sys_i32 w; 
    sys_i32 h;

    game_dialogue_screen_state state;
    sys_i32 state_progress;
    sys_i32 n_chars_shown;
    sys_i32 n_chars;
} game_dialogue_screen;

uint8_t game_dialogue_frame;

void game_dialogue_display(const char* text) {
    game_dialogue_screen.visible = true;
    game_dialogue_screen.dialogue = text;
    sys_measure_text(text, &game_dialogue_screen.w, &game_dialogue_screen.h);

    game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_BOB_IN;
    game_dialogue_screen.state_progress = 0;
    game_dialogue_screen.n_chars_shown = 0;
    game_dialogue_screen.n_chars = strlen(text);
    assert(game_dialogue_screen.n_chars <= GAME_DIALOGUE_MAX_N_CHARS);
}

void game_dialogue_update(bool* allow_input) {
    game_dialogue_frame = ((uint32_t) game_dialogue_frame + 1) & 0xff;

    if (
        game_dialogue_screen.visible && 
        game_dialogue_screen.state < GAME_DIALOGUE_SCREEN_STATE_BOB_OUT
    ) { 
        *allow_input = false;

        if (sys_btnp(DEVICE_BUTTON_0, false)) {
            if (game_dialogue_screen.state < GAME_DIALOGUE_SCREEN_STATE_WAIT) {
                game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_WAIT;
                game_dialogue_screen.n_chars_shown = game_dialogue_screen.n_chars;
            } else {
                game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_BOB_OUT;
                game_dialogue_screen.state_progress = 0;
            }
        }
    }

    switch (game_dialogue_screen.state) {
    case GAME_DIALOGUE_SCREEN_STATE_BOB_IN:
        game_dialogue_screen.state_progress += 25;
        if (game_dialogue_screen.state_progress >= 0x100) {
            game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_TYPEWRITER;
            game_dialogue_screen.state_progress = 0;
        }
        break;
    case GAME_DIALOGUE_SCREEN_STATE_TYPEWRITER: 
        if (game_dialogue_frame % 4 == 0) {
            game_dialogue_screen.n_chars_shown = sys_min_i32(
                game_dialogue_screen.n_chars_shown + 1,
                game_dialogue_screen.n_chars
            );
        }
        if (game_dialogue_screen.n_chars_shown >= game_dialogue_screen.n_chars) {
            game_dialogue_screen.state = GAME_DIALOGUE_SCREEN_STATE_WAIT;
        }
        break;
    case GAME_DIALOGUE_SCREEN_STATE_WAIT:
        break;
    case GAME_DIALOGUE_SCREEN_STATE_BOB_OUT:
        game_dialogue_screen.state_progress += 25;
        if (game_dialogue_screen.state_progress >= 0x100) {
            game_dialogue_screen.visible = false;
            game_dialogue_screen.state_progress = 0;
        }
    }
}
void game_dialogue_draw() {
    if (!game_dialogue_screen.visible) { return; }

    sys_i32 x = DEVICE_W / 2 - game_dialogue_screen.w / 2;
    sys_i32 y = DEVICE_H - game_dialogue_screen.h - 8;

    sys_i32 cx = DEVICE_W / 2;
    sys_i32 cy = DEVICE_H - game_dialogue_screen.h / 2 - 8;

    sys_i32 interp_amt = 0;
    switch (game_dialogue_screen.state) {
        case GAME_DIALOGUE_SCREEN_STATE_BOB_IN:
            interp_amt = 255 - game_dialogue_screen.state_progress;
            break;
        case GAME_DIALOGUE_SCREEN_STATE_BOB_OUT:
            interp_amt = game_dialogue_screen.state_progress;
            break;
        default:
            break;
    }

    int x0 = x - 4;
    int y0 = y - 4;
    int x1 = x + game_dialogue_screen.w + 4;
    int y1 = y + game_dialogue_screen.h + 4;

    sys_oval_fill(
        x0 + (cx - x0) * interp_amt / 256,
        y0 + (cy - y0) * interp_amt / 256,
        x1 + (cx - x1) * interp_amt / 256,
        y1 + (cy - y1) * interp_amt / 256,
        1
    );

    if (game_dialogue_screen.state == GAME_DIALOGUE_SCREEN_STATE_BOB_OUT) {
        return;
    }
    char chars[GAME_DIALOGUE_MAX_N_CHARS + 1];
    strcpy(chars, game_dialogue_screen.dialogue);
    chars[game_dialogue_screen.n_chars_shown] = 0;

    for (int dy = -1; dy <= 1; dy++) {
        for (int dx = -1; dx <= 1; dx++) {
            sys_print(chars, x+dx, y+dy, 0);
        }
    }
    sys_print(chars, x, y, 7);
}