#include "game/scenes/credits_scene.hpp"

#include <cstdio>
#include <cstdlib>

#include "core/audio/audio.hpp"
#include "core/jail/jdraw8.hpp"
#include "core/jail/jinput.hpp"
#include "game/info.hpp"
#include "game/scenes/scene_utils.hpp"

namespace {

    // Frames del cotxe: 8 posicions dins del sprite sheet gfx/final.gif. El
    // vell doCredits tenia aquesta taula inline — la reproduïm idèntica.
    struct CocheFrame {
        Uint16 x, y;
    };

    constexpr CocheFrame COCHE_FRAMES[8] = {
        {.x = 214, .y = 152},
        {.x = 214, .y = 104},
        {.x = 214, .y = 56},
        {.x = 214, .y = 104},
        {.x = 214, .y = 152},
        {.x = 214, .y = 8},
        {.x = 108, .y = 152},
        {.x = 214, .y = 8},
    };

    constexpr int CONTADOR_MAX = 3100;  // ~62 s de crèdits a 20 ms/tick
    constexpr int TICK_MS = 20;         // Jg::setUpdateTicks heretat del doSlides previ
    constexpr int BG_INDEX = 255;

}  // namespace

namespace Scenes {

    // No toquem la paleta activa: SetScreenPalette n'ha pres ownership.
    CreditsScene::~CreditsScene() = default;

    void CreditsScene::onEnter() {
        // El vell doCredits no tocava música — heretava la del doSlides
        // previ ("music/final.ogg"). Si l'escena s'arrenca directament (test
        // amb piramide_inicial=8) no hi ha res que heretar, així que
        // arranquem la mateixa pista només si no sona res. Inocu en el
        // flux normal: Ja::MusicState::PLAYING fa que no la tornem a tocar.
        if (Audio::getRealMusicState() != Audio::MusicState::PLAYING) {
            playMusic("music/final.ogg");
        }

        vaddr2_ = SurfaceHandle("gfx/final.gif");
        vaddr3_ = SurfaceHandle("gfx/finals.gif");

        Jd8::Palette pal = Jd8::loadPalette("gfx/final.gif");
        Jd8::setScreenPalette(pal);
        // `pal` passa a ser propietat de main_palette — no l'alliberem.

        phase_ = Phase::ROLLING;
        contador_ = 1;
        contador_acc_ms_ = 0;
    }

    void CreditsScene::render() {
        Jd8::clearScreen(BG_INDEX);

        // Columna 1: scroll vertical del bloc (0,0,80,200) pujant des de
        // y=200 fins que el contador supera 2750.
        if (contador_ < 2750) {
            Jd8::blitCKCut(115, 200 - (contador_ / 6), vaddr2_, 0, 0, 80, 200, 0);
        }

        // Columna 2: scroll vertical del bloc (85,0,120,140), arrenca
        // a contador 1200 i s'atura (fix en y=20) a partir de 2250.
        if ((contador_ > 1200) && (contador_ < 2280)) {
            Jd8::blitCKCut(100, 200 - ((contador_ - 1200) / 6), vaddr2_, 85, 0, 120, 140, 0);
        } else if (contador_ >= 2250) {
            Jd8::blitCK(100, 20, vaddr2_, 85, 0, 120, 140, 0);
        }

        // Fons: 4 capes parallax + cotxe només si l'usuari ha aconseguit
        // tots els diamants (final "bo"). Altrament fons estàtic.
        if (Info::ctx.diamants == 16) {
            Jd8::blitCKScroll(50, vaddr3_, ((contador_ >> 3) % 320) + 1, 0, 50, 255);
            Jd8::blitCKScroll(50, vaddr3_, ((contador_ >> 2) % 320) + 1, 50, 50, 255);
            Jd8::blitCKScroll(50, vaddr3_, ((contador_ >> 1) % 320) + 1, 100, 50, 255);
            Jd8::blitCKScroll(50, vaddr3_, (contador_ % 320) + 1, 150, 50, 255);

            const CocheFrame& cf = COCHE_FRAMES[coche_.frame()];
            Jd8::blitCK(100, 50, vaddr2_, cf.x, cf.y, 106, 48, 255);
        } else {
            Jd8::blitCK(0, 50, vaddr3_, 0, 0, 320, 50, 255);
            Jd8::blitCK(0, 50, vaddr3_, 0, 50, 320, 50, 255);
        }

        // Barres de marc que cobreixen els extrems del scroll vertical.
        Jd8::fillSquare(0, 50, BG_INDEX);
        Jd8::fillSquare(100, 10, BG_INDEX);
    }

    void CreditsScene::writeTrickIni() {
        FILE* ini = std::fopen("trick.ini", "wb");
        if (ini != nullptr) {
            std::fwrite("1", 1, 1, ini);
            std::fclose(ini);
        }
        Info::ctx.nou_personatge = true;
    }

    void CreditsScene::tick(int delta_ms) {
        switch (phase_) {
            case Phase::ROLLING: {
                // Avancem el contador en passos discrets de 20 ms, igual
                // que feia Jg::shouldUpdate(20) al vell doCredits.
                contador_acc_ms_ += delta_ms;
                while (contador_acc_ms_ >= TICK_MS) {
                    contador_acc_ms_ -= TICK_MS;
                    ++contador_;
                }

                coche_.tick(delta_ms);
                render();

                if (Ji::anyKey() || contador_ >= CONTADOR_MAX) {
                    writeTrickIni();
                    fade_.startFadeOut();
                    phase_ = Phase::FADING_OUT;
                }
                break;
            }

            case Phase::FADING_OUT:
                fade_.tick(delta_ms);
                if (fade_.done()) {
                    Info::ctx.num_piramide = 255;
                    phase_ = Phase::DONE;
                }
                break;

            case Phase::DONE:
                break;
        }
    }

}  // namespace Scenes
