#include "game/prota.hpp"

#include <cstdlib>

#include "core/jail/jgame.hpp"
#include "core/jail/jinput.hpp"

namespace {
    // Atura el frame.h a 10 quan piràmide 4 (sprite "petit" amb pijama de presoner).
    auto adjustedHeight(int base_h) -> int {
        return (Info::ctx.num_piramide == 4) ? base_h - 5 : base_h;
    }

    void addFrameGrid(Entitat& entitat, int x0, int x1, int x_step, int y0, int y1, int y_step, int w, int h, int skip_x = -1, int skip_y = -1) {
        for (int yy = y0; yy < y1; yy += y_step) {
            for (int xx = x0; xx < x1; xx += x_step) {
                if (xx == skip_x && yy == skip_y) {
                    continue;
                }
                Frame f;
                f.w = w;
                f.h = adjustedHeight(h);
                f.x = xx;
                f.y = yy;
                entitat.frames.push_back(f);
            }
        }
    }

    void buildProtaFrames(Entitat& entitat) {
        entitat.frames.reserve(82);
        // Cara/quatre direccions (4×5 sprites de 15×15 a y=20..)
        addFrameGrid(entitat, 0, 75, 15, 20, 80, 15, 15, 15);
        // Animació de mort (15×30 a y=95..; salta x=300/y=155)
        addFrameGrid(entitat, 60, 315, 15, 95, 185, 30, 15, 30, 300, 155);
        // Animació de victòria (15×15 a y=20.., x=225..)
        addFrameGrid(entitat, 225, 315, 15, 20, 50, 15, 15, 15);
    }

    void buildProtaAnimations(Entitat& entitat) {
        entitat.animacions.resize(6);
        for (int i = 0; i < 4; i++) {
            entitat.animacions[i].frames = {
                static_cast<Uint8>(0 + (i * 5)),
                static_cast<Uint8>(1 + (i * 5)),
                static_cast<Uint8>(2 + (i * 5)),
                static_cast<Uint8>(1 + (i * 5)),
                static_cast<Uint8>(0 + (i * 5)),
                static_cast<Uint8>(3 + (i * 5)),
                static_cast<Uint8>(4 + (i * 5)),
                static_cast<Uint8>(3 + (i * 5)),
            };
        }
        entitat.animacions[4].frames.resize(50);
        for (int i = 0; i < 50; i++) {
            entitat.animacions[4].frames[i] = i + 20;
        }
        entitat.animacions[5].frames.resize(48);
        for (int i = 0; i < 12; i++) {
            entitat.animacions[5].frames[i] = i + 70;
        }
        for (int i = 12; i < 48; i++) {
            entitat.animacions[5].frames[i] = 81;
        }
    }
}  // namespace

Prota::Prota(Jd8::Surface gfx)
    : Sprite(gfx) {
    buildProtaFrames(entitat);
    buildProtaAnimations(entitat);
    cur_frame = 0;
    x = 150;
    y = 30;
    o = 0;
    cycles_per_frame_ = 4;
    pergami = false;
    frame_pejades = 0;
}

void Prota::draw() {
    Sprite::draw();

    if (Info::ctx.num_piramide == 4 && this->o != 4) {
        if ((Jg::getCycleCounter() % 40) < 20) {
            Jd8::blitCK(this->x, this->y, this->gfx_, 220, 80, 15, 15, 255);
        } else {
            Jd8::blitCK(this->x, this->y, this->gfx_, 235, 80, 15, 15, 255);
        }
    }
}

auto Prota::readDirection() -> Uint8 {
    Uint8 dir = 4;
    if (Ji::keyPressed(SDL_SCANCODE_DOWN)) {
        if ((this->x - 20) % 65 == 0) { this->o = 0; }
        dir = this->o;
    }
    if (Ji::keyPressed(SDL_SCANCODE_UP)) {
        if ((this->x - 20) % 65 == 0) { this->o = 1; }
        dir = this->o;
    }
    if (Ji::keyPressed(SDL_SCANCODE_RIGHT)) {
        if ((this->y - 30) % 35 == 0) { this->o = 2; }
        dir = this->o;
    }
    if (Ji::keyPressed(SDL_SCANCODE_LEFT)) {
        if ((this->y - 30) % 35 == 0) { this->o = 3; }
        dir = this->o;
    }
    return dir;
}

void Prota::stepInDirection(Uint8 dir) {
    switch (dir) {
        case 0:
            if (this->y < 170) { this->y++; }
            break;
        case 1:
            if (this->y > 30) { this->y--; }
            break;
        case 2:
            if (this->x < 280) { this->x++; }
            break;
        case 3:
            if (this->x > 20) { this->x--; }
            break;
        default:
            break;
    }
}

void Prota::advanceWalkingFrame(Uint8 dir) {
    if (dir == 4) {
        this->cur_frame = 0;
        return;
    }
    this->frame_pejades++;
    if (this->frame_pejades == 15) {
        this->frame_pejades = 0;
    }
    if (Jg::getCycleCounter() % this->cycles_per_frame_ == 0) {
        this->cur_frame++;
        if (this->cur_frame == entitat.animacions[this->o].frames.size()) {
            this->cur_frame = 0;
        }
    }
}

auto Prota::advanceFinalAnimation() -> Uint8 {
    if (Jg::getCycleCounter() % this->cycles_per_frame_ != 0) {
        return 0;
    }
    this->cur_frame++;
    if (this->cur_frame != entitat.animacions[this->o].frames.size()) {
        return 0;
    }
    return (this->o == 4) ? 1 : 2;
}

auto Prota::update() -> Uint8 {
    if (this->o >= 4) {
        return advanceFinalAnimation();
    }
    const Uint8 DIR = readDirection();
    stepInDirection(DIR);
    advanceWalkingFrame(DIR);
    return 0;
}
