#include <emu.h>
#include <stdio.h>
#include <cart.h>
#include <cpu.h>
#include <ui.h>
#include <timer.h>
#include <dma.h>
#include <ppu.h>
#include <audio.h>

#ifdef _WIN32
#include <windows.h>
#else
#include <pthread.h>
#include <unistd.h>
#endif

static emu_context ctx;

emu_context *emu_get_context() {
    return &ctx;
}

#ifdef _WIN32
DWORD WINAPI cpu_run(void *p) {
#else
void *cpu_run(void *p) {
#endif
    ppu_init();
    timer_init();
    cpu_init();
    audio_init();

    ctx.running = true;
    ctx.paused = false;
    ctx.ticks = 0;

    while (ctx.running) {
        if (ctx.paused) {
            delay(10);
            continue;
        }

        if (!cpu_step()) {
            printf("CPU stopped\n");
            return 0;
        }

    }

    return 0;
}

void sleep_ms(int milis) {
#ifdef _WIN32
    Sleep(milis);
#else
   	usleep(milis * 1000);
#endif
}

int emu_run(int argc, char **argv) {
    if (argc < 2) {
        printf("Usage: gbemu <rom_file>\n");
        return -1;
    }

    if(!cart_load(argv[1])) {
        printf("Failed to load ROM file: %s\n", argv[1]);
        return -2;
    }
	
    printf("Cart loaded..\n");

    ui_init();
#ifdef _WIN32
    HANDLE thread = CreateThread(NULL, 0, cpu_run, NULL, 0, NULL);
    if(!thread) {
        fprintf(stderr, "Unable to create main CPU thread!\n");
        return -1;
    }
#else
   	pthread_t t1;
    if(pthread_create(&t1, NULL, cpu_run, NULL)) {
        fprintf(stderr, "Unable to create main CPU thread!\n");
        return -1;
    }
#endif

    u32 prev_frame = 0;

    while(!ctx.die) {
        sleep_ms(1);
        ui_handle_events();
        if (prev_frame != ppu_get_context()->current_frame) {
            ui_update();
        }
        prev_frame = ppu_get_context()->current_frame;
    }
    

    return 0;
}

void emu_cycles(int cpu_cycles) {
    for (int i = 0; i < cpu_cycles; i++){
        for(int n = 0; n < 4; n++){
            ctx.ticks++;
            timer_tick();
            ppu_tick();
        }
        dma_tick();
    }
}
