#include <vector>
#include <iostream>

#include "PhysicsEngine.hpp"
#include "IPhysicsComponent.hpp"
#include "RigidbodyComponent.hpp"

/**
 * Note: To run tests, uncomment main function at the bottom of this file and comment out the lab main function
 */

#define TESTNUM 8

// COLLISION DETECTION TESTS : IPhysicsComponent
bool TestOne(){
    TransformComponent* positionA = new TransformComponent(0,0);
    TransformComponent* positionB = new TransformComponent(1,2);
    IPhysicsComponent* componentA = new IPhysicsComponent(positionA, Vec2D(2,2));
    IPhysicsComponent* componentB = new IPhysicsComponent(positionB, Vec2D(2,2));

    return componentA->IsColliding(componentB);
}

bool TestTwo(){
    TransformComponent* positionA = new TransformComponent(0,0);
    TransformComponent* positionB = new TransformComponent(2,0);
    IPhysicsComponent* componentA = new IPhysicsComponent(positionA, Vec2D(2,2));
    IPhysicsComponent* componentB = new IPhysicsComponent(positionB, Vec2D(2,2));

    return componentA->IsColliding(componentB);
}

bool TestThree(){
    TransformComponent* positionA = new TransformComponent(1,2);
    TransformComponent* positionB = new TransformComponent(0,0);
    IPhysicsComponent* componentA = new IPhysicsComponent(positionA, Vec2D(2,2));
    IPhysicsComponent* componentB = new IPhysicsComponent(positionB, Vec2D(2,2));

    return componentA->IsColliding(componentB);
}

bool TestFour(){
    TransformComponent* positionA = new TransformComponent(0,0);
    TransformComponent* positionB = new TransformComponent(-2,2);
    IPhysicsComponent* componentA = new IPhysicsComponent(positionA, Vec2D(2,2));
    IPhysicsComponent* componentB = new IPhysicsComponent(positionB, Vec2D(2,2));

    return componentA->IsColliding(componentB);
}

// SIMPLE MOVEMENT TESTS : RigidbodyComponent
bool TestFive(){
    TransformComponent* position = new TransformComponent(0,0);
    RigidbodyComponent* body = new RigidbodyComponent(position, Vec2D(3,3), Vec2D(1,0), 1);

    body->ApplyVelocity();
    return position->getPos().x == 1 && position->getPos().y == 0;
}

bool TestSix(){
    TransformComponent* position = new TransformComponent(2,3);
    RigidbodyComponent* body = new RigidbodyComponent(position, Vec2D(3,3), Vec2D(1,0), 1);

    body->ApplyAcceleration(Vec2D(2,1));
    body->ApplyVelocity();
    return position->getPos().x == 5 && position->getPos().y == 4;
}

bool TestSeven(){
    TransformComponent* position = new TransformComponent(2,3);
    RigidbodyComponent* body = new RigidbodyComponent(position, Vec2D(3,3), Vec2D(1,0), 2);

    body->ApplyForce(Vec2D(4,2));
    body->ApplyVelocity();
    return position->getPos().x == 5 && position->getPos().y == 4;
}

// PHYSICS ENGINE TESTS

// Simplest collision test
bool TestEight(){
    PhysicsEngine* engine = new PhysicsEngine();
    TransformComponent* posA = new TransformComponent(0,0);
    RigidbodyComponent* bodyA = new RigidbodyComponent(posA, Vec2D(1,1), Vec2D(1,0), 1, true, false);
    TransformComponent* posB = new TransformComponent(2,0);
    RigidbodyComponent* bodyB = new RigidbodyComponent(posB, Vec2D(1,1), Vec2D(0,0), 1, true, false);
    engine->AddComponent(bodyA);
    engine->AddComponent(bodyB);
    engine->Update();
    if(bodyA->GetPosition().x != 1){
        std::cout << "Test Eight: Engine failed to move body A. Current x position is " << bodyA->GetPosition().x << std::endl;
        return false;
    }
    engine->Update();
    if(bodyA->GetVelocity().x != 0){
        std::cout << "Test Eight: Engine failed to bounce body A. Current velocity is: " << bodyA->GetVelocity().x << " " << bodyA->GetVelocity().y << std::endl;
        return false;
    }
    if(bodyB->GetVelocity().x != 1){
        std::cout << "Test Eight: Engine failed to bounce body B. Current velocity is: " << bodyB->GetVelocity().x << " " << bodyB->GetVelocity().y << std::endl;
        return false;
    }
    return bodyA->GetPosition().x == 1 && bodyB->GetPosition().x == 3;
}

// int main(){
//     int correct = 0;

//     bool(*(tests[TESTNUM]))() = {TestOne,
//                                 TestTwo,
//                                 TestThree,
//                                 TestFour,
//                                 TestFive,
//                                 TestSix,
//                                 TestSeven,
//                                 TestEight};

//     for(int i = 0; i < TESTNUM; ++i){
//         if(tests[i]()){
//             ++correct;
//         } else {
//             std::cout << "Test number " << i+1 << " failed" << std::endl;
//         }
//     }

//     std::cout << correct << " tests passed out of " << TESTNUM << std::endl;

//     return 0;
// }


