const std = @import("std");
const r = @import("raylib.zig");
const assets = @import("assets.zig");
const Funge = @import("funge.zig");

const Walrus = @This();

pub const Direction = Funge.Direction;

pub fn init(name: []const u8) !Walrus {
    const tex = try assets.getTexture(name);
    const pos = r.Vector2{ .x = 0, .y = 0 };
    return Walrus{
        .tex = tex,
        .dir = .East,
        .pos = pos,
        .actualpos = pos,
        .offset = r.Vector2{ .x = 32, .y = 32 },
        .isMoving = false,
        .bounds = r.Rectangle{ .x = 0, .y = 0, .width = 640, .height = 480 },
        .size = r.Rectangle{ .x = 4, .y = 4, .width = 24, .height = 24 },
        .frames = 2,
    };
}

tex: r.Texture2D,
dir: Direction,
pos: r.Vector2,
actualpos: r.Vector2,
offset: r.Vector2,
isMoving: bool,
bounds: r.Rectangle,
size: r.Rectangle,
frames: f32,

pub fn deinit(self: *@This()) void {
    r.UnloadTexture(self.tex);
}

pub fn spawn(self: *@This(), pos: r.Vector2, dir: Direction) void {
    self.pos = pos;
    self.actualpos = pos;
    self.dir = dir;
}

pub fn correctBounds(self: *@This(), pos: r.Vector2) r.Vector2 {
    return r.Vector2{
        .x = @mod(pos.x - self.bounds.x, self.bounds.width) + self.bounds.x,
        .y = @mod(pos.y - self.bounds.y, self.bounds.height) + self.bounds.y,
    };
}

pub fn update(self: *@This()) void {
    if (self.isMoving) {
        switch (self.dir) {
            .West => {
                self.actualpos.x -= 1;
            },
            .North => {
                self.actualpos.y -= 1;
            },
            .East => {
                self.actualpos.x += 1;
            },
            .South => {
                self.actualpos.y += 1;
            },
        }
        self.actualpos = self.correctBounds(self.actualpos);
        if (self.pos.x == self.actualpos.x and self.pos.y == self.actualpos.y) self.isMoving = false;
    }
}

pub fn moveDir(self: *@This(), direction: Direction) void {
    self.dir = direction;
    self.move();
}

pub fn move(self: *@This()) void {
    self.isMoving = true;
    switch (self.dir) {
        .West => self.pos.x -= self.offset.x,
        .North => self.pos.y -= self.offset.y,
        .East => self.pos.x += self.offset.x,
        .South => self.pos.y += self.offset.y,
    }
    self.pos = self.correctBounds(self.pos);
}

pub fn moveRel(self: *@This(), pos: r.Vector2) void {
    self.pos.x += self.offset.x * pos.x;
    self.pos.y += self.offset.y * pos.y;
    self.pos = self.correctBounds(self.pos);
    self.actualpos = self.pos;
}

pub fn moveAbs(self: *@This(), pos: r.Vector2) void {
    self.pos.x = self.offset.x * pos.x;
    self.pos.y = self.offset.y * pos.y;
    self.pos = self.correctBounds(self.pos);
    self.actualpos = self.pos;
}

pub fn draw(self: *@This()) void {
    r.DrawTextureRec(
        self.tex,
        r.Rectangle{
            .x = @floor(@mod((self.actualpos.x + self.actualpos.y) / 4, self.frames)) * self.size.width,
            .y = self.dir.spritePosY(self.size.height),
            .width = self.size.width,
            .height = self.size.height,
        },
        r.Vector2{
            .x = self.actualpos.x + self.size.x,
            .y = self.actualpos.y + self.size.y,
        },
        r.WHITE,
    );
}
