# Game Client in Suicmez
# Full rewrite of the C client using Suicmez language

struct SuicVec3
    x: float,
    y: float,
    z: float,
end

struct SuicColor
    r: u8,
    g: u8,
    b: u8,
    a: u8,
end

struct SuicDirectionalLight
    direction: SuicVec3,
    color: SuicVec3,
    intensity: float,
    ambientIntensity: float,
    shadowBias: float,
    shadowIntensity: float,
end

# Constants
const PISTOL_FIRE_RATE = 4.0
const RIFLE_FIRE_RATE = 12.0
const RECOIL_RETURN = 18.0
const CROSS_RETURN = 14.0
const PISTOL_KICK_PITCH = 0.010
const PISTOL_KICK_YAW = 0.004
const RIFLE_KICK_PITCH = 0.018
const RIFLE_KICK_YAW = 0.010
const PISTOL_CROSS_KICK = 2.0
const RIFLE_CROSS_KICK = 4.0
const PISTOL_SPRAY_GROW = 0.4
const RIFLE_SPRAY_GROW = 1.2
const BURST_RESET_TIME = 0.18

const SUIC_BTN_RELOAD = 1
const SUIC_BTN_SWITCH_PISTOL = 2
const SUIC_BTN_SWITCH_RIFLE = 4
const SUIC_BTN_PICK = 8
const SUIC_BTN_USE_MEDKIT = 16
const SUIC_BTN_JUMP = 32

const SUIC_WEAPON_PISTOL = 0
const SUIC_WEAPON_RIFLE = 1

const SUIC_ITEM_MEDKIT = 1
const SUIC_ITEM_AMMO_PISTOL = 2
const SUIC_ITEM_AMMO_RIFLE = 3

const SUIC_TERRAIN_SIZE = 256.0
const SUIC_TERRAIN_SCALE = 1.0
const SUIC_TERRAIN_MIN = -256.0 * 1.0 / 2.0
const SUIC_TERRAIN_MAX = 256.0 * 1.0 / 2.0

const SUIC_NET_MAX_PLAYERS = 16
const SUIC_NET_USERNAME_MAX = 16
const SUIC_NET_MAX_ITEMS = 64

struct GameState
    cam_pos: SuicVec3,
    yaw: float,
    pitch: float,
    prev_body_pos: SuicVec3,
    current_target_body: SuicVec3,
    interp_timer: float,
    recoil_yaw: float,
    recoil_pitch: float,
    cross_spread: float,
    scoped: bool,
    fire_cooldown: float,
    shots_in_burst: int,
    burst_reset_timer: float,
    client_tick: int,
    light: SuicDirectionalLight,
end

fn suic_game_init(game_state: *GameState, username: string, server_ip: string, port: int) -> () do
    suic_terrain_init()
    suic_net_init(server_ip, port)
    suic_net_send_hello(username)
    disable_cursor()
end

fn suic_game_shutdown() -> () do
    suic_terrain_cleanup()
    suic_net_shutdown()
end

fn suic_game_handle_input(game_state: *GameState, dt: float) -> () do
    game_state.client_tick = game_state.client_tick + 1

    # Cooldowns
    game_state.fire_cooldown = game_state.fire_cooldown - dt
    if game_state.fire_cooldown < 0.0 do
        game_state.fire_cooldown = 0.0
    end
    game_state.burst_reset_timer = game_state.burst_reset_timer - dt
    if game_state.burst_reset_timer <= 0.0 do
        game_state.shots_in_burst = 0
    end

    # Recoil recovery
    let k = 1.0 - expf(-RECOIL_RETURN * dt)
    game_state.recoil_yaw = game_state.recoil_yaw + (0.0 - game_state.recoil_yaw) * k
    game_state.recoil_pitch = game_state.recoil_pitch + (0.0 - game_state.recoil_pitch) * k

    let k2 = 1.0 - expf(-CROSS_RETURN * dt)
    game_state.cross_spread = game_state.cross_spread + (0.0 - game_state.cross_spread) * k2
    if game_state.cross_spread < 0.01 do
        game_state.cross_spread = 0.0
    end

    # Mouse look
    let md = get_mouse_delta()
    let sens = 0.0025
    game_state.yaw = game_state.yaw - md.x * sens
    game_state.pitch = game_state.pitch - md.y * sens
    if game_state.pitch < -1.5 do
        game_state.pitch = -1.5
    end
    if game_state.pitch > 1.5 do
        game_state.pitch = 1.5
    end

    # Movement input
    let mut move_x = 0.0
    let mut move_z = 0.0
    if is_key_down(65) do  # KEY_A
        move_x = move_x + 1.0
    end
    if is_key_down(68) do  # KEY_D
        move_x = move_x - 1.0
    end
    if is_key_down(87) do  # KEY_W
        move_z = move_z + 1.0
    end
    if is_key_down(83) do  # KEY_S
        move_z = move_z - 1.0
    end

    # Buttons
    let mut buttons = 0
    if is_key_pressed(82) do  # KEY_R
        buttons = buttons bitor SUIC_BTN_RELOAD
    end
    if is_key_pressed(49) do  # KEY_ONE
        buttons = buttons bitor SUIC_BTN_SWITCH_PISTOL
    end
    if is_key_pressed(50) do  # KEY_TWO
        buttons = buttons bitor SUIC_BTN_SWITCH_RIFLE
    end
    if is_key_pressed(70) do  # KEY_F
        buttons = buttons bitor SUIC_BTN_PICK
    end
    if is_key_pressed(72) do  # KEY_H
        buttons = buttons bitor SUIC_BTN_USE_MEDKIT
    end
    if is_key_pressed(32) do  # KEY_SPACE
        buttons = buttons bitor SUIC_BTN_JUMP
    end
    if is_key_pressed(90) do  # KEY_Z
        game_state.scoped = not game_state.scoped
    end

    let my_id = suic_net_get_my_id()
    let view_yaw = game_state.yaw + game_state.recoil_yaw
    let view_pitch = game_state.pitch + game_state.recoil_pitch
    let mut clamped_view_pitch = view_pitch
    if clamped_view_pitch < -1.5 do
        clamped_view_pitch = -1.5
    end
    if clamped_view_pitch > 1.5 do
        clamped_view_pitch = 1.5
    end

    if my_id != 255 do
        suic_net_send_input(my_id, game_state.client_tick, move_x, move_z, view_yaw, clamped_view_pitch, buttons)
    end

    # Shooting
    if my_id != 255 and is_mouse_button_down(0) and game_state.fire_cooldown <= 0.0 and suic_net_player_present(my_id) do
        let wpn = suic_net_player_weapon(my_id)
        let mut rate = RIFLE_FIRE_RATE
        if wpn == SUIC_WEAPON_PISTOL do
            rate = PISTOL_FIRE_RATE
        end
        game_state.fire_cooldown = 1.0 / rate

        game_state.shots_in_burst = game_state.shots_in_burst + 1
        game_state.burst_reset_timer = BURST_RESET_TIME

        if wpn == SUIC_WEAPON_PISTOL do
            game_state.recoil_pitch = game_state.recoil_pitch + PISTOL_KICK_PITCH
            game_state.recoil_yaw = game_state.recoil_yaw + (get_random_value(-1000, 1000) as float / 1000.0) * PISTOL_KICK_YAW
            game_state.cross_spread = game_state.cross_spread + PISTOL_CROSS_KICK + game_state.shots_in_burst as float * PISTOL_SPRAY_GROW
        end
        if wpn == SUIC_WEAPON_RIFLE do
            game_state.recoil_pitch = game_state.recoil_pitch + RIFLE_KICK_PITCH
            game_state.recoil_yaw = game_state.recoil_yaw + (get_random_value(-1000, 1000) as float / 1000.0) * RIFLE_KICK_YAW
            game_state.cross_spread = game_state.cross_spread + RIFLE_CROSS_KICK + game_state.shots_in_burst as float * RIFLE_SPRAY_GROW
        end

        suic_net_send_shoot(my_id, game_state.client_tick)
    end
end

fn suic_game_update(game_state: *GameState, dt: float) -> () do
    suic_net_poll()

    let my_id = suic_net_get_my_id()
    if my_id != 255 and suic_net_player_present(my_id) do
        game_state.prev_body_pos = game_state.current_target_body
        game_state.current_target_body = suic_v3(suic_net_player_x(my_id),
                                                suic_net_player_y(my_id),
                                                suic_net_player_z(my_id))
        game_state.interp_timer = 0.0
    end

    # Interpolate camera
    if my_id != 255 and suic_net_player_present(my_id) do
        let mut interp_factor = game_state.interp_timer / (1.0 / 20.0)
        if interp_factor > 1.0 do
            interp_factor = 1.0
        end
        let interp_body = suic_v3_add(suic_v3_mul(game_state.prev_body_pos, 1.0 - interp_factor),
                                     suic_v3_mul(game_state.current_target_body, interp_factor))
        game_state.cam_pos.x = interp_body.x
        game_state.cam_pos.y = interp_body.y + 1.0
        game_state.cam_pos.z = interp_body.z + 0.0001

        let terrain_h = suic_terrain_height(game_state.cam_pos.x, game_state.cam_pos.z)
        game_state.cam_pos.y = fmaxf(game_state.cam_pos.y, terrain_h + 1.5)
    end
    game_state.interp_timer = game_state.interp_timer + dt

    # Forward offset
    if my_id != 255 do
        let view_yaw = game_state.yaw + game_state.recoil_yaw
        let view_pitch = game_state.pitch + game_state.recoil_pitch
        let forward = suic_v3(sinf(view_yaw) * cosf(view_pitch), sinf(view_pitch),
                             cosf(view_yaw) * cosf(view_pitch))
        game_state.cam_pos = suic_v3_add(game_state.cam_pos, suic_v3_mul(forward, 0.3))
        game_state.cam_pos.y = game_state.cam_pos.y - 0.2
    end

    let terrain_h = suic_terrain_height(game_state.cam_pos.x, game_state.cam_pos.z)
    game_state.cam_pos.y = fmaxf(game_state.cam_pos.y, terrain_h + 1.5)
end

fn suic_game_render(game_state: *GameState) -> () do
    let sw = get_screen_width()
    let sh = get_screen_height()
    let my_id = suic_net_get_my_id()

    let view_yaw = game_state.yaw + game_state.recoil_yaw
    let view_pitch = game_state.pitch + game_state.recoil_pitch
    let mut clamped_view_pitch = view_pitch
    if clamped_view_pitch < -1.5 do
        clamped_view_pitch = -1.5
    end
    if clamped_view_pitch > 1.5 do
        clamped_view_pitch = 1.5
    end

    let forward = suic_v3(sinf(view_yaw) * cosf(clamped_view_pitch), sinf(clamped_view_pitch),
                         cosf(view_yaw) * cosf(clamped_view_pitch))

    # Camera setup (simplified - need to implement Camera3D struct)
    let mut fov = 75.0
    if game_state.scoped do
        fov = 30.0
    end
    begin_mode3d(game_state.cam_pos.x, game_state.cam_pos.y, game_state.cam_pos.z,
                 game_state.cam_pos.x + forward.x, game_state.cam_pos.y + forward.y, game_state.cam_pos.z + forward.z,
                 0.0, 1.0, 0.0, fov, 0)

    # Terrain
    suic_terrain_draw(game_state.cam_pos)

    # Border
    let border_size = SUIC_TERRAIN_MAX - SUIC_TERRAIN_MIN
    draw_cube(0.0, 0.0, 0.0, border_size, 1000.0, border_size, 255, 0, 0, 100)

    # Items
    let mut i = 0
    while i < SUIC_NET_MAX_ITEMS do
        if suic_net_item_present(i) do
            let mut ic_r = 220
            let mut ic_g = 220
            let mut ic_b = 220
            let item_type = suic_net_item_type(i)
            if item_type == SUIC_ITEM_MEDKIT do
                ic_r = 120
                ic_g = 255
                ic_b = 120
            end
            if item_type == SUIC_ITEM_AMMO_PISTOL do
                ic_r = 255
                ic_g = 220
                ic_b = 120
            end
            if item_type == SUIC_ITEM_AMMO_RIFLE do
                ic_r = 255
                ic_g = 180
                ic_b = 120
            end

            let item_pos = suic_v3(suic_net_item_x(i), suic_net_item_y(i), suic_net_item_z(i))
            let item_normal = suic_v3(0.0, 1.0, 0.0)
            let base_color = SuicColor { r: ic_r as u8, g: ic_g as u8, b: ic_b as u8, a: 255 }
            let lit_color = suic_light_apply_shadows(base_color, item_normal, item_pos, game_state.light)
            draw_sphere(item_pos.x, item_pos.y, item_pos.z, 0.3, lit_color.r as int, lit_color.g as int, lit_color.b as int, lit_color.a as int)
        end
        i = i + 1
    end

    # Players
    i = 0
    while i < SUIC_NET_MAX_PLAYERS do
        if suic_net_player_present(i) do
            let mut interp_factor = game_state.interp_timer / (1.0 / 20.0)
            if interp_factor > 1.0 do
                interp_factor = 1.0
            end
            let prev = suic_v3(suic_net_player_prev_x(i), suic_net_player_prev_y(i), suic_net_player_prev_z(i))
            let curr = suic_v3(suic_net_player_x(i), suic_net_player_y(i), suic_net_player_z(i))
            let p = suic_v3_add(suic_v3_mul(prev, 1.0 - interp_factor), suic_v3_mul(curr, interp_factor))

            let mut c_r = 255
            let mut c_g = 80
            let mut c_b = 80
            if i == my_id do
                c_r = 80
                c_g = 180
                c_b = 255
            end
            if not suic_net_player_alive(i) do
                c_r = 120
                c_g = 120
                c_b = 120
            end

            let player_normal = suic_v3(0.0, 1.0, 0.0)
            let base_color = SuicColor { r: c_r as u8, g: c_g as u8, b: c_b as u8, a: 255 }
            let lit_color = suic_light_apply_shadows(base_color, player_normal, p, game_state.light)
            draw_capsule(p.x, p.y - 0.5, p.z, p.x, p.y + 0.5, p.z, 0.35, 8, 8, lit_color.r as int, lit_color.g as int, lit_color.b as int, lit_color.a as int)
        end
        i = i + 1
    end

    end_mode3d()

    # Nameplates
    i = 0
    while i < SUIC_NET_MAX_PLAYERS do
        if suic_net_player_present(i) do
            let mut interp_factor = game_state.interp_timer / (1.0 / 20.0)
            if interp_factor > 1.0 do
                interp_factor = 1.0
            end
            let prev = suic_v3(suic_net_player_prev_x(i), suic_net_player_prev_y(i), suic_net_player_prev_z(i))
             let curr = suic_v3(suic_net_player_x(i), suic_net_player_y(i), suic_net_player_z(i))
             let p = suic_v3_add(suic_v3_mul(prev, 1.0 - interp_factor), suic_v3_mul(curr, interp_factor))

             suic_ui_draw_nameplate(sw, sh, p.x, p.y, p.z, suic_net_player_username(i), i == my_id,
                                    g_cam_pos.x, g_cam_pos.y, g_cam_pos.z,
                                    g_cam_pos.x + forward.x, g_cam_pos.y + forward.y, g_cam_pos.z + forward.z)
        i = i + 1
    end

    # HUD
    if my_id == 255 or not suic_net_player_present(my_id) do
        draw_text("Offline", 10, 10, 20, 255, 255, 255, 255)
    end
    if my_id != 255 and suic_net_player_present(my_id) do
        let weapon = suic_net_player_weapon(my_id)
        let mut mag = suic_net_player_rifle_mag(my_id)
        let mut reserve = suic_net_player_rifle_ammo(my_id)
        if weapon == SUIC_WEAPON_PISTOL do
            mag = suic_net_player_pistol_mag(my_id)
            reserve = suic_net_player_pistol_ammo(my_id)
        end
        suic_ui_draw_hud(suic_net_player_hp(my_id), weapon, mag, reserve, suic_net_player_medkits(my_id), suic_net_player_reload_time(my_id))
    end

    draw_fps(sw - 90, 10)

    # Room state
    suic_ui_draw_room_state(sw, sh, suic_net_room_state(), suic_net_countdown(), suic_net_winner_name())

    # Crosshair
    suic_ui_draw_crosshair(sw, sh, game_state.cross_spread, game_state.scoped)
end

fn main() -> int do
    let zero_vec = SuicVec3 { x: 0.0, y: 0.0, z: 0.0 }
    let default_light = SuicDirectionalLight { direction: zero_vec, color: zero_vec, intensity: 0.0, ambientIntensity: 0.0, shadowBias: 0.0, shadowIntensity: 0.0 }
    # Game state
    let mut game_state = GameState {
        cam_pos: SuicVec3 { x: 0.0, y: 5.0, z: 6.0 },
        yaw: 0.0,
        pitch: 0.0,
        prev_body_pos: SuicVec3 { x: 0.0, y: 5.0, z: 6.0 },
        current_target_body: SuicVec3 { x: 0.0, y: 5.0, z: 6.0 },
        interp_timer: 0.0,
        recoil_yaw: 0.0,
        recoil_pitch: 0.0,
        cross_spread: 0.0,
        scoped: false,
        fire_cooldown: 0.0,
        shots_in_burst: 0,
        burst_reset_timer: 0.0,
        client_tick: 0,
        light: default_light
    }

    let screen_w = 1280
    let screen_h = 720

    init_window(screen_w, screen_h, "Voxel Shooter Client")
    defer close_window()
    set_target_fps(120)
    disable_cursor()

    game_state.light = suic_light_create_default()

    # Get username
    let mut username = ""
    suic_ui_username_prompt(&username, SUIC_NET_USERNAME_MAX)

    # Initialize game subsystems
    suic_game_init(&game_state, username, "127.0.0.1", 27015)

    # Main loop
    while window_should_close() == false do
        let dt = get_frame_time()

        suic_game_handle_input(&game_state, dt)
        suic_game_update(&game_state, dt)

        begin_drawing()
        clear_background(135, 206, 235, 255)

        suic_game_render(&game_state)

        end_drawing()
    end

    suic_game_shutdown()

    0
end
