#include "game/scenes/secreta_scene.hpp"

#include <algorithm>
#include <cstdlib>
#include <cstring>

#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 {

    constexpr int TICK_MS = 20;  // Jg::setUpdateTicks(20) del vell doSecreta

    // Durades per fase, derivades dels CONTADOR-thresholds del vell:
    //   tomba1 scroll: 127 passos (CONTADOR 1→128) × 20ms
    //   tomba1 hold:   128 passos (CONTADOR 128→0) × 20ms
    //   tomba2 scroll: 94 passos × 20ms
    //   tomba2 hold:   94 passos × 20ms
    //   reveal horit:  80 passos × 20ms
    //   reveal hold:   80 passos × 20ms
    //   red pulse:     51 passos × 20ms
    //   red pulse hold: 51 passos × 20ms
    constexpr int TOMBA1_SCROLL_MS = 127 * TICK_MS;
    constexpr int TOMBA1_HOLD_MS = 128 * TICK_MS;
    constexpr int TOMBA2_SCROLL_MS = 94 * TICK_MS;
    constexpr int TOMBA2_HOLD_MS = 94 * TICK_MS;
    constexpr int TOMBA2_REVEAL_MS = 80 * TICK_MS;
    constexpr int TOMBA2_REVEAL_HOLD_MS = 80 * TICK_MS;
    constexpr int RED_PULSE_MS = 51 * TICK_MS;
    constexpr int RED_PULSE_HOLD_MS = 51 * TICK_MS;

}  // namespace

namespace Scenes {

    SecretaScene::~SecretaScene() {
        delete[] pal_aux_;
        // pal_active_ NO s'allibera: propietat de main_palette via SetScreenPalette.
    }

    void SecretaScene::onEnter() {
        playMusic("music/secreta.ogg");

        // Fade-out de la paleta anterior. Els assets es carreguen ja
        // però no fem SetScreenPalette fins que acabe el fade — així
        // el fade opera sobre la paleta del mòdul anterior.
        fade_.startFadeOut();

        gfx_ = SurfaceHandle("gfx/tomba1.gif");
        pal_aux_ = Jd8::loadPalette("gfx/tomba1.gif");
        pal_active_ = new Color[256];
        std::memcpy(pal_active_, pal_aux_, 768);

        phase_ = Phase::INITIAL_FADE_OUT;
        phase_acc_ms_ = 0;
    }

    void SecretaScene::swapToTomba2() {
        Jd8::clearScreen(255);
        gfx_.reset("gfx/tomba2.gif");

        delete[] pal_aux_;
        pal_aux_ = Jd8::loadPalette("gfx/tomba2.gif");
        // pal_active_ continua sent el mateix buffer: només actualitzem
        // el seu contingut. main_palette ja apunta ací.
        std::memcpy(pal_active_, pal_aux_, 768);
    }

    void SecretaScene::beginRedPulseSetup() {
        Jd8::clearScreen(0);
        Jd8::setPaletteColor(254, 12, 11, 11);
        Jd8::setPaletteColor(253, 12, 11, 11);
    }

    void SecretaScene::beginFinalFade() {
        Audio::get()->fadeOutMusic(250);
        fade_.startFadeOut();
        phase_ = Phase::FINAL_FADE_OUT;
    }

    void SecretaScene::tick(int delta_ms) {
        // Skip per tecla (després del fade inicial, no mentre). Salta
        // directament al FINAL_FADE_OUT. Mateix patró que el vell, on
        // qualsevol tecla sortia del loop.
        if (!skip_triggered_ && phase_ != Phase::INITIAL_FADE_OUT && Ji::anyKey()) {
            skip_triggered_ = true;
            beginFinalFade();
        }

        switch (phase_) {
            case Phase::INITIAL_FADE_OUT:
                fade_.tick(delta_ms);
                if (fade_.done()) {
                    // Ara main_palette (la vella) té tots els canals a 0.
                    // SetScreenPalette allibera la vella i adopta pal_active_
                    // — des d'ara main_palette == pal_active_, així que les
                    // futures escriptures a pal_active_ afecten la pantalla.
                    Jd8::setScreenPalette(pal_active_);
                    Jd8::clearScreen(255);
                    phase_ = Phase::TOMBA1_SCROLL_IN;
                    phase_acc_ms_ = 0;
                }
                break;

            case Phase::TOMBA1_SCROLL_IN: {
                phase_acc_ms_ += delta_ms;
                const int CONTADOR = std::min(128, (phase_acc_ms_ / TICK_MS) + 1);
                // Dos blits solapats: el primer avança a velocitat completa,
                // el segon (contingut de la dreta del src) a meitat (CONTADOR>>1).
                Jd8::blit(70, 60, gfx_, 0, CONTADOR, 178, 70);
                Jd8::blitCK(70, 60, gfx_, 178, CONTADOR >> 1, 142, 70, 255);
                if (phase_acc_ms_ >= TOMBA1_SCROLL_MS) {
                    phase_ = Phase::TOMBA1_HOLD;
                    phase_acc_ms_ = 0;
                }
                break;
            }

            case Phase::TOMBA1_HOLD:
                phase_acc_ms_ += delta_ms;
                if (phase_acc_ms_ >= TOMBA1_HOLD_MS) {
                    swapToTomba2();
                    phase_ = Phase::TOMBA2_SCROLL_IN;
                    phase_acc_ms_ = 0;
                }
                break;

            case Phase::TOMBA2_SCROLL_IN: {
                phase_acc_ms_ += delta_ms;
                const int CONTADOR = std::min(94, (phase_acc_ms_ / TICK_MS) + 1);
                Jd8::blit(55, 53, gfx_, 0, 158 - CONTADOR, 211, CONTADOR);
                if (phase_acc_ms_ >= TOMBA2_SCROLL_MS) {
                    phase_ = Phase::TOMBA2_HOLD;
                    phase_acc_ms_ = 0;
                }
                break;
            }

            case Phase::TOMBA2_HOLD:
                phase_acc_ms_ += delta_ms;
                if (phase_acc_ms_ >= TOMBA2_HOLD_MS) {
                    beginRedPulseSetup();
                    phase_ = Phase::TOMBA2_REVEAL;
                    phase_acc_ms_ = 0;
                }
                break;

            case Phase::TOMBA2_REVEAL: {
                phase_acc_ms_ += delta_ms;
                const int CONTADOR = std::min(80, (phase_acc_ms_ / TICK_MS) + 1);
                // Revelat horitzontal simètric: l'amplada creix 2px per tick
                // i el src_x es desplaça a l'esquerra el mateix.
                Jd8::blit(80, 68, gfx_, 160 - (CONTADOR * 2), 0, CONTADOR * 2, 64);
                if (phase_acc_ms_ >= TOMBA2_REVEAL_MS) {
                    phase_ = Phase::TOMBA2_REVEAL_HOLD;
                    phase_acc_ms_ = 0;
                }
                break;
            }

            case Phase::TOMBA2_REVEAL_HOLD:
                phase_acc_ms_ += delta_ms;
                if (phase_acc_ms_ >= TOMBA2_REVEAL_HOLD_MS) {
                    phase_ = Phase::RED_PULSE;
                    phase_acc_ms_ = 0;
                }
                break;

            case Phase::RED_PULSE: {
                phase_acc_ms_ += delta_ms;
                const int CONTADOR = std::min(51, phase_acc_ms_ / TICK_MS);
                // Anima el canal R dels índexs 254 i 253 (aquest a la meitat
                // de brillantor). Va de (12,11,11) fins a (63,11,11) / (31,11,11).
                Jd8::setPaletteColor(254, CONTADOR + 12, 11, 11);
                Jd8::setPaletteColor(253, (CONTADOR + 12) >> 1, 11, 11);
                if (phase_acc_ms_ >= RED_PULSE_MS) {
                    phase_ = Phase::RED_PULSE_HOLD;
                    phase_acc_ms_ = 0;
                }
                break;
            }

            case Phase::RED_PULSE_HOLD:
                phase_acc_ms_ += delta_ms;
                if (phase_acc_ms_ >= RED_PULSE_HOLD_MS) {
                    beginFinalFade();
                }
                break;

            case Phase::FINAL_FADE_OUT:
                fade_.tick(delta_ms);
                if (fade_.done()) {
                    phase_ = Phase::DONE;
                }
                break;

            case Phase::DONE:
                break;
        }
    }

}  // namespace Scenes
