#include <iostream>
#include <ostream>
#include <DangerousRacers/Scenes/Levels/tutorial_level.h>

#include "SFML/Window/Event.hpp"

TutorialLevelScene::TutorialLevelScene (SceneManager& _sceneManager) : Scene (_sceneManager, "DebugLevelScene") {
    backgroundTexture.loadFromFile("assets/racing_bg.png");
    backgroundSprite.setTexture(backgroundTexture);
    backgroundSprite.setPosition(0, -720);

    obstacleManager.allowRandomSpawn = false;
    player.tutorialMode = true;
}

void TutorialLevelScene::leave() {
    sceneManager.getGameWindow().setMouseCursorVisible(true);
}

void TutorialLevelScene::reset() {
    obstacleManager.reset();
    reverseTime = false;
    bgYOffset = -720.f;
    speed = 200.f;

    player.moveTo(405.f/2, 720.f/2, 0.f);
}

void TutorialLevelScene::start() {
    Scene::start();
    reset();
    sceneManager.getGameWindow().setMouseCursorVisible(false);


    obstacleManager.spawnObstacle(48, -100.f, Obstacle::ObstacleType::WALL);
    obstacleManager.spawnObstacle(405*0.5f, -500.f, Obstacle::ObstacleType::CONE);
    obstacleManager.spawnObstacle(405-48, -900.f, Obstacle::ObstacleType::WALL);
}

void TutorialLevelScene::update (const float deltaTime) {
    if (reverseTime && timeInReverse >= 2.5f) reverseTime = false;
    const float delta = reverseTime ? -deltaTime : deltaTime;

    Scene::update(delta);
    // Update player movement before anything else
    player.update(delta);

    // Check for collisions
    if (!reverseTime && !player.isInvincible() && obstacleManager.obstacleCollides(player.getSprite().getGlobalBounds())) {
        std::cout << "Collision!\n";
        if (player.tutorialMode) {
            reverseTime = true;
            timeInReverse = 0.f;
        } else {
            health -= 0.1f;
            if (health <= 0) speed = 50.f;
            player.setInvincibility(1.5f);
        }
    }

    if (!player.isInvincible() && health <= 0) {
        // Tutorial Over
        sceneManager.changeScene("TutorialOverScene");
        return;
    }

    // Scroll BG
    bgYOffset += delta * speed;
    if (bgYOffset >= 0) bgYOffset = -720.f;
    else if (bgYOffset < -720.f) bgYOffset = 0.f;
    backgroundSprite.setPosition(0, bgYOffset);

    // Move obstacles (and maybe spawn?)
    obstacleManager.update(delta);

    if (reverseTime) timeInReverse += std::abs(delta);
    distanceTraveled += delta * speed;
    scoreLabel.setText("Distance: " + std::to_string(static_cast<int>(distanceTraveled)));

    fuel -= delta * 0.025f;
    if (fuel <= 0) {
        // Tutorial Over
        sceneManager.changeScene("TutorialOverScene");
        return;
    }

    fuelMeter.setValue(fuel);
    damageMeter.setValue(health);

    if (currentTutorial >= tutorialDistance.size()) {
        player.tutorialMode = false;
        obstacleManager.allowRandomSpawn = true;
        return;
    }
    if (distanceTraveled >= tutorialDistance[currentTutorial]) currentTutorial++;
}

void TutorialLevelScene::render (sf::RenderWindow& window) {
    Scene::render (window);
    window.draw(backgroundSprite);

    obstacleManager.render(window);

    // Draw player here, to be on top of obstacles
    player.render(window);

    // Draw UI components last
    scoreLabel.render(window);

    if (currentTutorial >= 1) fuelMeter.render(window);
    if (currentTutorial >= 2) damageMeter.render(window);

    if (currentTutorial >= tutorialLabels.size()) return;
    tutorialLabels[currentTutorial].render(window);
}

void TutorialLevelScene::eventHandler (sf::Event& event) {
    Scene::eventHandler (event);

    if (event.type == sf::Event::KeyPressed && event.key.code == sf::Keyboard::Escape) {
        this->sceneManager.changeScene("MainMenu");
        return;
    }

    if (reverseTime) {
        const sf::Vector2 playerPos = player.getPosition();
        player.moveTo(playerPos.x, playerPos.y, 0.f);
        return;
    }

    if (event.type == sf::Event::MouseMoved)
        player.moveTo(std::clamp(event.mouseMove.x, 32, 373), player.getPosition().y, 0.025f);
}