const std = @import("std");
pub const c = @import("c.zig").c;

pub const JoystickConnectionState = enum(c_int) {
    joystickConnectionUnknown,
    joystickConnectionWired,
    joystickConnectionWireless,
};

pub const GUID = extern struct {
    data: [16]u8,
};

pub const PropertiesID = u32;

pub const IOStream = opaque {
    pub inline fn addGamepadMappingsFromIO(iostream: *IOStream, closeio: bool) c_int {
        return c.SDL_AddGamepadMappingsFromIO(iostream, @bitCast(closeio));
    }
};

pub const JoystickID = u32;

pub const SensorType = enum(c_int) {
    sensorInvalid = -1, //Returned for an invalid sensor
    sensorUnknown, //Unknown sensor type
    sensorAccel, //Accelerometer
    sensorGyro, //Gyroscope
    sensorAccelL, //Accelerometer for left Joy-Con controller and Wii nunchuk
    sensorGyroL, //Gyroscope for left Joy-Con controller
    sensorAccelR, //Accelerometer for right Joy-Con controller
    sensorGyroR, //Gyroscope for right Joy-Con controller
    sensorCount,
};

pub const PowerState = enum(c_int) {
    powerstateError = -1, //error determining power status
    powerstateUnknown, //cannot determine power status
    powerstateOnBattery, //Not plugged in, running on the battery
    powerstateNoBattery, //Plugged in, no battery available
    powerstateCharging, //Plugged in, charging battery
    powerstateCharged,
};

pub const Joystick = opaque {};

pub const Gamepad = opaque {
    pub inline fn getGamepadMapping(gamepad: *Gamepad) [*c]u8 {
        return c.SDL_GetGamepadMapping(gamepad);
    }

    pub inline fn getGamepadProperties(gamepad: *Gamepad) PropertiesID {
        return c.SDL_GetGamepadProperties(gamepad);
    }

    pub inline fn getGamepadID(gamepad: *Gamepad) JoystickID {
        return c.SDL_GetGamepadID(gamepad);
    }

    pub inline fn getGamepadName(gamepad: *Gamepad) [*c]const u8 {
        return c.SDL_GetGamepadName(gamepad);
    }

    pub inline fn getGamepadPath(gamepad: *Gamepad) [*c]const u8 {
        return c.SDL_GetGamepadPath(gamepad);
    }

    pub inline fn getGamepadType(gamepad: *Gamepad) GamepadType {
        return @intFromEnum(c.SDL_GetGamepadType(gamepad));
    }

    pub inline fn getRealGamepadType(gamepad: *Gamepad) GamepadType {
        return @intFromEnum(c.SDL_GetRealGamepadType(gamepad));
    }

    pub inline fn getGamepadPlayerIndex(gamepad: *Gamepad) c_int {
        return c.SDL_GetGamepadPlayerIndex(gamepad);
    }

    pub inline fn setGamepadPlayerIndex(gamepad: *Gamepad, player_index: c_int) bool {
        return @bitCast(c.SDL_SetGamepadPlayerIndex(gamepad, player_index));
    }

    pub inline fn getGamepadVendor(gamepad: *Gamepad) u16 {
        return c.SDL_GetGamepadVendor(gamepad);
    }

    pub inline fn getGamepadProduct(gamepad: *Gamepad) u16 {
        return c.SDL_GetGamepadProduct(gamepad);
    }

    pub inline fn getGamepadProductVersion(gamepad: *Gamepad) u16 {
        return c.SDL_GetGamepadProductVersion(gamepad);
    }

    pub inline fn getGamepadFirmwareVersion(gamepad: *Gamepad) u16 {
        return c.SDL_GetGamepadFirmwareVersion(gamepad);
    }

    pub inline fn getGamepadSerial(gamepad: *Gamepad) [*c]const u8 {
        return c.SDL_GetGamepadSerial(gamepad);
    }

    pub inline fn getGamepadSteamHandle(gamepad: *Gamepad) u64 {
        return c.SDL_GetGamepadSteamHandle(gamepad);
    }

    pub inline fn getGamepadConnectionState(gamepad: *Gamepad) JoystickConnectionState {
        return c.SDL_GetGamepadConnectionState(gamepad);
    }

    pub inline fn getGamepadPowerInfo(gamepad: *Gamepad, percent: *c_int) PowerState {
        return c.SDL_GetGamepadPowerInfo(gamepad, @ptrCast(percent));
    }

    pub inline fn gamepadConnected(gamepad: *Gamepad) bool {
        return @bitCast(c.SDL_GamepadConnected(gamepad));
    }

    pub inline fn getGamepadJoystick(gamepad: *Gamepad) ?*Joystick {
        return c.SDL_GetGamepadJoystick(gamepad);
    }

    pub inline fn getGamepadBindings(gamepad: *Gamepad, count: *c_int) [*c][*c]GamepadBinding {
        return c.SDL_GetGamepadBindings(gamepad, @ptrCast(count));
    }

    pub inline fn gamepadHasAxis(gamepad: *Gamepad, axis: GamepadAxis) bool {
        return @bitCast(c.SDL_GamepadHasAxis(gamepad, axis));
    }

    pub inline fn getGamepadAxis(gamepad: *Gamepad, axis: GamepadAxis) i16 {
        return c.SDL_GetGamepadAxis(gamepad, axis);
    }

    pub inline fn gamepadHasButton(gamepad: *Gamepad, button: GamepadButton) bool {
        return @bitCast(c.SDL_GamepadHasButton(gamepad, button));
    }

    pub inline fn getGamepadButton(gamepad: *Gamepad, button: GamepadButton) bool {
        return @bitCast(c.SDL_GetGamepadButton(gamepad, button));
    }

    pub inline fn getGamepadButtonLabel(gamepad: *Gamepad, button: GamepadButton) GamepadButtonLabel {
        return c.SDL_GetGamepadButtonLabel(gamepad, button);
    }

    pub inline fn getNumGamepadTouchpads(gamepad: *Gamepad) c_int {
        return c.SDL_GetNumGamepadTouchpads(gamepad);
    }

    pub inline fn getNumGamepadTouchpadFingers(gamepad: *Gamepad, touchpad: c_int) c_int {
        return c.SDL_GetNumGamepadTouchpadFingers(gamepad, touchpad);
    }

    pub inline fn getGamepadTouchpadFinger(gamepad: *Gamepad, touchpad: c_int, finger: c_int, down: *bool, x: *f32, y: *f32, pressure: *f32) bool {
        return @bitCast(c.SDL_GetGamepadTouchpadFinger(gamepad, touchpad, finger, @ptrCast(down), @ptrCast(x), @ptrCast(y), @ptrCast(pressure)));
    }

    pub inline fn gamepadHasSensor(gamepad: *Gamepad, _type: SensorType) bool {
        return @bitCast(c.SDL_GamepadHasSensor(gamepad, @intFromEnum(_type)));
    }

    pub inline fn setGamepadSensorEnabled(gamepad: *Gamepad, _type: SensorType, enabled: bool) bool {
        return @bitCast(c.SDL_SetGamepadSensorEnabled(gamepad, @intFromEnum(_type), @bitCast(enabled)));
    }

    pub inline fn gamepadSensorEnabled(gamepad: *Gamepad, _type: SensorType) bool {
        return @bitCast(c.SDL_GamepadSensorEnabled(gamepad, @intFromEnum(_type)));
    }

    pub inline fn getGamepadSensorDataRate(gamepad: *Gamepad, _type: SensorType) f32 {
        return c.SDL_GetGamepadSensorDataRate(gamepad, @intFromEnum(_type));
    }

    pub inline fn getGamepadSensorData(gamepad: *Gamepad, _type: SensorType, data: *f32, num_values: c_int) bool {
        return @bitCast(c.SDL_GetGamepadSensorData(gamepad, @intFromEnum(_type), @ptrCast(data), num_values));
    }

    pub inline fn rumbleGamepad(gamepad: *Gamepad, low_frequency_rumble: u16, high_frequency_rumble: u16, duration_ms: u32) bool {
        return @bitCast(c.SDL_RumbleGamepad(gamepad, low_frequency_rumble, high_frequency_rumble, duration_ms));
    }

    pub inline fn rumbleGamepadTriggers(gamepad: *Gamepad, left_rumble: u16, right_rumble: u16, duration_ms: u32) bool {
        return @bitCast(c.SDL_RumbleGamepadTriggers(gamepad, left_rumble, right_rumble, duration_ms));
    }

    pub inline fn setGamepadLED(gamepad: *Gamepad, red: u8, green: u8, blue: u8) bool {
        return @bitCast(c.SDL_SetGamepadLED(gamepad, red, green, blue));
    }

    pub inline fn sendGamepadEffect(gamepad: *Gamepad, data: ?*const anyopaque, size: c_int) bool {
        return @bitCast(c.SDL_SendGamepadEffect(gamepad, data, size));
    }

    pub inline fn closeGamepad(gamepad: *Gamepad) void {
        return c.SDL_CloseGamepad(gamepad);
    }

    pub inline fn getGamepadAppleSFSymbolsNameForButton(gamepad: *Gamepad, button: GamepadButton) [*c]const u8 {
        return c.SDL_GetGamepadAppleSFSymbolsNameForButton(gamepad, button);
    }

    pub inline fn getGamepadAppleSFSymbolsNameForAxis(gamepad: *Gamepad, axis: GamepadAxis) [*c]const u8 {
        return c.SDL_GetGamepadAppleSFSymbolsNameForAxis(gamepad, axis);
    }
};

pub const GamepadType = enum(c_int) {
    gamepadTypeStandard,
    gamepadTypeXbox360,
    gamepadTypeXboxone,
    gamepadTypePs3,
    gamepadTypePs4,
    gamepadTypePs5,
    gamepadTypeNintendoSwitchPro,
    gamepadTypeNintendoSwitchJoyconLeft,
    gamepadTypeNintendoSwitchJoyconRight,
    gamepadTypeNintendoSwitchJoyconPair,
    gamepadTypeCount,
};

pub const GamepadButton = enum(c_int) {
    gamepadButtonSouth, //Bottom face button (e.g. Xbox A button)
    gamepadButtonEast, //Right face button (e.g. Xbox B button)
    gamepadButtonWest, //Left face button (e.g. Xbox X button)
    gamepadButtonNorth, //Top face button (e.g. Xbox Y button)
    gamepadButtonBack,
    gamepadButtonGuide,
    gamepadButtonStart,
    gamepadButtonLeftStick,
    gamepadButtonRightStick,
    gamepadButtonLeftShoulder,
    gamepadButtonRightShoulder,
    gamepadButtonDpadUp,
    gamepadButtonDpadDown,
    gamepadButtonDpadLeft,
    gamepadButtonDpadRight,
    gamepadButtonMisc1, //Additional button (e.g. Xbox Series X share button, PS5 microphone button, Nintendo Switch Pro capture button, Amazon Luna microphone button, Google Stadia capture button)
    gamepadButtonRightPaddle1, //Upper or primary paddle, under your right hand (e.g. Xbox Elite paddle P1)
    gamepadButtonLeftPaddle1, //Upper or primary paddle, under your left hand (e.g. Xbox Elite paddle P3)
    gamepadButtonRightPaddle2, //Lower or secondary paddle, under your right hand (e.g. Xbox Elite paddle P2)
    gamepadButtonLeftPaddle2, //Lower or secondary paddle, under your left hand (e.g. Xbox Elite paddle P4)
    gamepadButtonTouchpad, //PS4/PS5 touchpad button
    gamepadButtonMisc2, //Additional button
    gamepadButtonMisc3, //Additional button
    gamepadButtonMisc4, //Additional button
    gamepadButtonMisc5, //Additional button
    gamepadButtonMisc6, //Additional button
    gamepadButtonCount,
};

pub const GamepadButtonLabel = enum(c_int) {
    gamepadButtonLabelUnknown,
    gamepadButtonLabelA,
    gamepadButtonLabelB,
    gamepadButtonLabelX,
    gamepadButtonLabelY,
    gamepadButtonLabelCross,
    gamepadButtonLabelCircle,
    gamepadButtonLabelSquare,
    gamepadButtonLabelTriangle,
};

pub const GamepadAxis = enum(c_int) {
    gamepadAxisLeftx,
    gamepadAxisLefty,
    gamepadAxisRightx,
    gamepadAxisRighty,
    gamepadAxisLeftTrigger,
    gamepadAxisRightTrigger,
    gamepadAxisCount,
};

pub const GamepadBindingType = enum(c_int) {
    gamepadBindtypeButton,
    gamepadBindtypeAxis,
    gamepadBindtypeHat,
};

pub const GamepadBinding = opaque {};

pub inline fn addGamepadMapping(mapping: [*c]const u8) c_int {
    return c.SDL_AddGamepadMapping(mapping);
}

pub inline fn addGamepadMappingsFromFile(file: [*c]const u8) c_int {
    return c.SDL_AddGamepadMappingsFromFile(file);
}

pub inline fn reloadGamepadMappings() bool {
    return @bitCast(c.SDL_ReloadGamepadMappings());
}

pub inline fn getGamepadMappings(count: *c_int) [*c][*c]u8 {
    return c.SDL_GetGamepadMappings(@ptrCast(count));
}

pub inline fn getGamepadMappingForGUID(guid: GUID) [*c]u8 {
    return c.SDL_GetGamepadMappingForGUID(guid);
}

pub inline fn setGamepadMapping(instance_id: JoystickID, mapping: [*c]const u8) bool {
    return @bitCast(c.SDL_SetGamepadMapping(instance_id, mapping));
}

pub inline fn hasGamepad() bool {
    return @bitCast(c.SDL_HasGamepad());
}

pub inline fn getGamepads(count: *c_int) ?*JoystickID {
    return c.SDL_GetGamepads(@ptrCast(count));
}

pub inline fn isGamepad(instance_id: JoystickID) bool {
    return @bitCast(c.SDL_IsGamepad(instance_id));
}

pub inline fn getGamepadNameForID(instance_id: JoystickID) [*c]const u8 {
    return c.SDL_GetGamepadNameForID(instance_id);
}

pub inline fn getGamepadPathForID(instance_id: JoystickID) [*c]const u8 {
    return c.SDL_GetGamepadPathForID(instance_id);
}

pub inline fn getGamepadPlayerIndexForID(instance_id: JoystickID) c_int {
    return c.SDL_GetGamepadPlayerIndexForID(instance_id);
}

pub inline fn getGamepadGUIDForID(instance_id: JoystickID) GUID {
    return c.SDL_GetGamepadGUIDForID(instance_id);
}

pub inline fn getGamepadVendorForID(instance_id: JoystickID) u16 {
    return c.SDL_GetGamepadVendorForID(instance_id);
}

pub inline fn getGamepadProductForID(instance_id: JoystickID) u16 {
    return c.SDL_GetGamepadProductForID(instance_id);
}

pub inline fn getGamepadProductVersionForID(instance_id: JoystickID) u16 {
    return c.SDL_GetGamepadProductVersionForID(instance_id);
}

pub inline fn getGamepadTypeForID(instance_id: JoystickID) GamepadType {
    return @intFromEnum(c.SDL_GetGamepadTypeForID(instance_id));
}

pub inline fn getRealGamepadTypeForID(instance_id: JoystickID) GamepadType {
    return @intFromEnum(c.SDL_GetRealGamepadTypeForID(instance_id));
}

pub inline fn getGamepadMappingForID(instance_id: JoystickID) [*c]u8 {
    return c.SDL_GetGamepadMappingForID(instance_id);
}

pub inline fn openGamepad(instance_id: JoystickID) ?*Gamepad {
    return c.SDL_OpenGamepad(instance_id);
}

pub inline fn getGamepadFromID(instance_id: JoystickID) ?*Gamepad {
    return c.SDL_GetGamepadFromID(instance_id);
}

pub inline fn getGamepadFromPlayerIndex(player_index: c_int) ?*Gamepad {
    return c.SDL_GetGamepadFromPlayerIndex(player_index);
}

pub inline fn setGamepadEventsEnabled(enabled: bool) void {
    return c.SDL_SetGamepadEventsEnabled(@bitCast(enabled));
}

pub inline fn gamepadEventsEnabled() bool {
    return @bitCast(c.SDL_GamepadEventsEnabled());
}

pub inline fn updateGamepads() void {
    return c.SDL_UpdateGamepads();
}

pub inline fn getGamepadTypeFromString(str: [*c]const u8) GamepadType {
    return @intFromEnum(c.SDL_GetGamepadTypeFromString(str));
}

pub inline fn getGamepadStringForType(_type: GamepadType) [*c]const u8 {
    return c.SDL_GetGamepadStringForType(@intFromEnum(_type));
}

pub inline fn getGamepadAxisFromString(str: [*c]const u8) GamepadAxis {
    return c.SDL_GetGamepadAxisFromString(str);
}

pub inline fn getGamepadStringForAxis(axis: GamepadAxis) [*c]const u8 {
    return c.SDL_GetGamepadStringForAxis(axis);
}

pub inline fn getGamepadButtonFromString(str: [*c]const u8) GamepadButton {
    return c.SDL_GetGamepadButtonFromString(str);
}

pub inline fn getGamepadStringForButton(button: GamepadButton) [*c]const u8 {
    return c.SDL_GetGamepadStringForButton(button);
}

pub inline fn getGamepadButtonLabelForType(_type: GamepadType, button: GamepadButton) GamepadButtonLabel {
    return c.SDL_GetGamepadButtonLabelForType(@intFromEnum(_type), button);
}
