const std = @import("std");
const sdl = @import("sdl.zig").c;
const atils = @import("./asset_utils.zig");
const gs = @import("./game_state.zig");
const assert = std.debug.assert;
const SCREEN_WIDTH = 640;
const SCREEN_HEIGHT = 480;
const log = sdl.SDL_Log;
const GameText = @import("./text.zig").GameText;
const RGBAColor = @import("./utils/rgb_color.zig").RGBAColor;
const Timer = @import("./utils/timer.zig").Timer;

var window: *sdl.struct_SDL_Window = undefined;
// var screen_surface: *sdl.struct_SDL_Surface = undefined;
var renderer: *sdl.struct_SDL_Renderer = undefined;

const Offset = struct {
    x: i32,
    y: i32,
};
var img_pos: Offset = .{ .x = 0, .y = 0 };

pub fn main() !void {
    errdefer |err| if (err == error.SdlError) std.log.err("SDL error: {s}", .{sdl.SDL_GetError()});
    try init();
    defer close();
    var gpa = std.heap.GeneralPurposeAllocator(.{}){};
    const allocator = gpa.allocator();

    const bg_texture = try atils.loadTexture(renderer, "assets/background.png");
    defer sdl.SDL_DestroyTexture(bg_texture);

    try GameText.initFont();
    defer GameText.deinitFont();

    // var slime_factory = try sf.SlimeFactory.init(allocator, renderer);
    // defer slime_factory.deinit();
    // try slime_factory.add(.{});

    var game_state = try gs.GameState.init(allocator, renderer);
    defer game_state.deinit();

    var quit = false;
    var shifted = false;
    var start_time: u32 = 0;
    var timer = Timer{};
    while (!quit) {
        var event: sdl.SDL_Event = undefined;
        while (sdl.SDL_PollEvent(&event) != 0) {
            switch (event.type) {
                sdl.SDL_QUIT => {
                    quit = true;
                },
                sdl.SDL_KEYUP => {
                    switch (event.key.keysym.sym) {
                        sdl.SDLK_LSHIFT => {
                            shifted = false;
                        },
                        else => {},
                    }
                },
                sdl.SDL_KEYDOWN => {
                    switch (event.key.keysym.sym) {
                        sdl.SDLK_RETURN => {
                            start_time = sdl.SDL_GetTicks();
                        },
                        sdl.SDLK_s => {
                            if (timer.status == .started) timer.stop() else timer.start();
                        },
                        sdl.SDLK_p => {
                            if (timer.status == .paused) timer.unpause() else timer.pause();
                        },
                        // sdl.SDLK_UP => {
                        //     img_pos.y = img_pos.y - 5;
                        // },
                        // sdl.SDLK_DOWN => {
                        //     img_pos.y = img_pos.y + 5;
                        // },
                        // sdl.SDLK_LEFT => {
                        //     img_pos.x = img_pos.x - 5;
                        // },
                        // sdl.SDLK_RIGHT => {
                        //     img_pos.x = img_pos.x + 5;
                        // },
                        else => {},
                    }
                    log("Got key event: %i\n", event.key.keysym.sym);
                },
                else => {},
            }
        }
        _ = sdl.SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);
        _ = sdl.SDL_RenderClear(renderer);
        _ = sdl.SDL_RenderCopy(renderer, bg_texture, null, null);
        game_state.update_tick();
        var text = try GameText.loadFromRenderedText("Press S to start / stop", RGBAColor.whiteSmoke().tosdl());
        try text.render(
            &game_state,
            .{ .x = @intCast(game_state.SCREEN_WIDTH - text.w), .y = 2 },
        );
        text = try GameText.loadFromRenderedText("Press P to pause / unpause", RGBAColor.whiteSmoke().tosdl());
        try text.render(
            &game_state,
            .{ .x = @intCast(game_state.SCREEN_WIDTH - text.w), .y = 24 },
        );

        var buf: [8]u8 = undefined;
        const timer_ms = timer.getTicks();
        // const timer_base = std.math.log10(timer_ms) + 3;
        const time_str: []const u8 = try std.fmt.bufPrint(&buf, "{d}ms", .{timer_ms});
        var time_text = try GameText.loadFromRenderedText(time_str, RGBAColor.whiteSmoke().tosdl());
        try time_text.render(
            &game_state,
            .{ .x = @intCast(game_state.SCREEN_WIDTH - time_text.w), .y = 64 },
        );

        // Render red rect
        // const fill_rect: sdl.struct_SDL_Rect = sdl.SDL_Rect{ .x = SCREEN_WIDTH / 4, .y = SCREEN_HEIGHT / 4, .w = SCREEN_WIDTH / 2 + img_pos.x, .h = SCREEN_HEIGHT / 2 + img_pos.y };
        // _ = sdl.SDL_SetRenderDrawColor(renderer, 0xff, 0x00, 0x00, 0xff);
        // _ = sdl.SDL_RenderFillRect(renderer, &fill_rect);
        // _ = sdl.SDL_RenderSetViewport(renderer, &.{ .x = SCREEN_WIDTH / 2, .y = SCREEN_HEIGHT / 2, .w = SCREEN_WIDTH, .h = SCREEN_HEIGHT / 2 });
        // _ = sdl.SDL_RenderCopy(renderer, texture, null, null);
        _ = sdl.SDL_RenderPresent(renderer);
        // var dest_rect = sdl.SDL_Rect{ .x = src_rect.x + img_pos.x, .y = src_rect.y + img_pos.y, .w = SCREEN_WIDTH, .h = SCREEN_HEIGHT };
        // _ = sdl.SDL_BlitScaled(zig_image, &src_rect, screen_surface, &dest_rect);

        // _ = sdl.SDL_UpdateWindowSurface(window);
        sdl.SDL_Delay(100);
    }
    return;
}

fn init() !void {
    // Init SDL with video subsystem flag
    if (sdl.SDL_Init(sdl.SDL_INIT_VIDEO) < 0) {
        log("Unable to initialize SDL: %s\n", sdl.SDL_GetError());
        return error.SDLInitializationFailed;
    }

    const opt_window = sdl.SDL_CreateWindow("Game Window", sdl.SDL_WINDOWPOS_UNDEFINED, sdl.SDL_WINDOWPOS_UNDEFINED, SCREEN_WIDTH, SCREEN_HEIGHT, sdl.SDL_WINDOW_SHOWN);
    if (opt_window == null) {
        log("Unable to initialize SDL window: %s\n", sdl.SDL_GetError());
        return error.SDLInitializationFailed;
    }
    window = opt_window.?;

    renderer = sdl.SDL_CreateRenderer(window, -1, sdl.SDL_RENDERER_ACCELERATED) orelse {
        log("Unable to initialize SDL window: %s\n", sdl.SDL_GetError());
        return error.SDLInitializationFailed;
    };
    _ = sdl.SDL_SetRenderDrawColor(renderer, 0xff, 0xff, 0xff, 0xff);

    // screen_surface = sdl.SDL_GetWindowSurface(window);

    const img_flags = sdl.IMG_INIT_PNG;
    if (sdl.IMG_Init(img_flags) != img_flags) {
        // NOTE remember that errors with SDL_Image will be in IMG_GetError() not SDL_GetError()
        log("Unable to initialize SDL Image: %s\n", sdl.IMG_GetError());
        return error.SDLInitializationFailed;
    }

    if (sdl.TTF_Init() < 0) {
        log("Unable to initialize SDL TTF: %s\n", sdl.TTF_GetError());
        return error.SDLInitializationFailed;
    }
}

fn close() void {
    sdl.SDL_DestroyRenderer(renderer);
    sdl.SDL_DestroyWindow(window);
    sdl.IMG_Quit();
    sdl.TTF_Quit();
    sdl.SDL_Quit();
}
