package com.kangacult.octogone;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.assets.loaders.ModelLoader;
import com.badlogic.gdx.assets.loaders.ModelLoader.ModelParameters;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g3d.Material;
import com.badlogic.gdx.graphics.g3d.Model;
import com.badlogic.gdx.graphics.g3d.ModelBatch;
import com.badlogic.gdx.graphics.g3d.ModelInstance;
import com.badlogic.gdx.graphics.g3d.attributes.TextureAttribute;
import com.badlogic.gdx.math.MathUtils;
import com.badlogic.gdx.math.Matrix4;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.bullet.collision.Collision;
import com.badlogic.gdx.physics.bullet.collision.btBroadphaseProxy;
import com.badlogic.gdx.physics.bullet.collision.btCapsuleShapeZ;
import com.badlogic.gdx.physics.bullet.collision.btCollisionObject;
import com.badlogic.gdx.physics.bullet.dynamics.btDynamicsWorld;
import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody;
import com.badlogic.gdx.physics.bullet.dynamics.btRigidBody.btRigidBodyConstructionInfo;
import com.kangacult.octogone.Audio.SoundType;

public class Player {

    public btCapsuleShapeZ shape;
    public Animation idle;
    public Animation death;
    public Animation dead;
    public Animation runF;
    public Animation runR;
    public Animation runL;
    public Animation runB;
    public Texture waterBallTex;

    public float radius = 0.25f;
    public float height = 1.0f;

    public ModelInstance model;
    public ModelInstance shadow;
    public ModelInstance waterBall;
    public btRigidBody body;
    public MotionState motion;
    public Animation currentAnimation;
    public Vector3 directon = new Vector3();
    public float speed = 5f;

    public Vector3 direction = new Vector3();
    public Vector3 position = new Vector3();
    public Vector3 velocity = new Vector3();
    public float yaw;
    public float armed;
    /**Wave attack. */
    public Wave wave = new Wave();
    public boolean alive = true;

    public Vector3 cameraPosition = new Vector3();
    public Vector3 waterBallPosition = new Vector3();

    public float walkSoundsTime = 0.0f;
    public float walkSoundsDelta = 0.3f;
    public boolean openingLinePlayed = false;


    public void init(btDynamicsWorld world, Model quadModel, ModelLoader<ModelParameters> loader) {
        //Init Textures and animations
        waterBallTex = new Texture(Gdx.files.internal("WaterBall.png"));
        {//Idle
            Texture[] textures = new Texture[] {
                    new Texture(Gdx.files.internal("Player/Idle/Water_Girl_Animation00.png")),
                    new Texture(Gdx.files.internal("Player/Idle/Water_Girl_Animation01.png")),
                    new Texture(Gdx.files.internal("Player/Idle/Water_Girl_Animation02.png")),
                    new Texture(Gdx.files.internal("Player/Idle/Water_Girl_Animation03.png")),
                    new Texture(Gdx.files.internal("Player/Idle/Water_Girl_Animation04.png")),
                    new Texture(Gdx.files.internal("Player/Idle/Water_Girl_Animation05.png")),
                    new Texture(Gdx.files.internal("Player/Idle/Water_Girl_Animation06.png")),
            };
            float[] frames = new float[] {
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
            };
            idle = new Animation(textures, frames);
        }

        {//Run Forward
            Texture[] textures = new Texture[] {
                    new Texture(Gdx.files.internal("Player/RunF/Water_Girl_Animation00.png")),
                    new Texture(Gdx.files.internal("Player/RunF/Water_Girl_Animation01.png")),
                    new Texture(Gdx.files.internal("Player/RunF/Water_Girl_Animation02.png")),
                    new Texture(Gdx.files.internal("Player/RunF/Water_Girl_Animation03.png")),
                    new Texture(Gdx.files.internal("Player/RunF/Water_Girl_Animation04.png")),
                    new Texture(Gdx.files.internal("Player/RunF/Water_Girl_Animation05.png")),
            };
            float[] frames = new float[] {
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
            };
            runF = new Animation(textures, frames);
        }

        {//Die
            Texture[] textures = new Texture[] {
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation00.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation01.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation02.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation03.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation04.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation05.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation06.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation07.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation08.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation09.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation10.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation11.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation12.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation13.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation14.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation15.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation16.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation17.png")),
            };
            float[] frames = new float[] {
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
            };
            death = new Animation(textures, frames);
        }

        {//Dead
            Texture[] textures = new Texture[] {
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation17.png")),
                    new Texture(Gdx.files.internal("Player/Death/Water_Girl__DeathAnimation16.png")),
            };
            float[] frames = new float[] {
                    5.0f,
                    0.1f,
            };
            dead = new Animation(textures, frames);
        }

        {//Run Right
            Texture[] textures = new Texture[] {
                    new Texture(Gdx.files.internal("Player/RunR/Water_Girl_Animation00.png")),
                    new Texture(Gdx.files.internal("Player/RunR/Water_Girl_Animation01.png")),
                    new Texture(Gdx.files.internal("Player/RunR/Water_Girl_Animation02.png")),
                    new Texture(Gdx.files.internal("Player/RunR/Water_Girl_Animation03.png")),
                    new Texture(Gdx.files.internal("Player/RunR/Water_Girl_Animation04.png")),
                    new Texture(Gdx.files.internal("Player/RunR/Water_Girl_Animation05.png")),
            };
            float[] frames = new float[] {
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
            };
            runR = new Animation(textures, frames);
        }

        {//Run Left
            Texture[] textures = new Texture[] {
                    new Texture(Gdx.files.internal("Player/RunL/Water_Girl_Animation00.png")),
                    new Texture(Gdx.files.internal("Player/RunL/Water_Girl_Animation01.png")),
                    new Texture(Gdx.files.internal("Player/RunL/Water_Girl_Animation02.png")),
                    new Texture(Gdx.files.internal("Player/RunL/Water_Girl_Animation03.png")),
                    new Texture(Gdx.files.internal("Player/RunL/Water_Girl_Animation04.png")),
                    new Texture(Gdx.files.internal("Player/RunL/Water_Girl_Animation05.png")),
            };
            float[] frames = new float[] {
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
            };
            runL = new Animation(textures, frames);
        }


        {//Run Back
            Texture[] textures = new Texture[] {
                    new Texture(Gdx.files.internal("Player/RunB/Water_Girl_Animation_Back00.png")),
                    new Texture(Gdx.files.internal("Player/RunB/Water_Girl_Animation_Back01.png")),
                    new Texture(Gdx.files.internal("Player/RunB/Water_Girl_Animation_Back02.png")),
                    new Texture(Gdx.files.internal("Player/RunB/Water_Girl_Animation_Back03.png")),
                    new Texture(Gdx.files.internal("Player/RunB/Water_Girl_Animation_Back04.png")),
                    new Texture(Gdx.files.internal("Player/RunB/Water_Girl_Animation_Back05.png")),
            };
            float[] frames = new float[] {
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
                    0.06f,
            };
            runB = new Animation(textures, frames);
        }

        position.z = height/2f;
        shape = new btCapsuleShapeZ(radius, height - radius * 2f);

        motion = new MotionState(new Matrix4());
        model = new ModelInstance(quadModel);
        shadow = new ModelInstance(quadModel);
        waterBall = new ModelInstance(quadModel);
        TextureAttribute wd = (TextureAttribute) waterBall.materials.get(0).get(TextureAttribute.Diffuse);
        wd.textureDescription.texture = waterBallTex;
        waterBall.materials.get(0).set(wd);

        btRigidBodyConstructionInfo info =
                new btRigidBodyConstructionInfo(0f, motion, shape, new Vector3());
        body = new btRigidBody(info);
        info.dispose();
        body.setCollisionFlags(body.getCollisionFlags() | 
                btCollisionObject.CollisionFlags.CF_KINEMATIC_OBJECT);
        body.setActivationState(Collision.DISABLE_DEACTIVATION);
        body.activate();
        world.addRigidBody(body, 
                (short) btBroadphaseProxy.CollisionFilterGroups.CharacterFilter, 
                (short) btBroadphaseProxy.CollisionFilterGroups.AllFilter);

        wave.init(loader, world);
        reset();
    }

    public void reset() {
        position.set(0f, 0f, height/2f);
        direction.setZero();
        velocity.setZero();
        currentAnimation = idle;
        alive = true;
        armed = 0f;
        yaw = 0f;
        wave.reset();
        openingLinePlayed = false;
    }

    public void dispose(btDynamicsWorld world) {
        world.removeRigidBody(body);
        shape.dispose();
        body.dispose();
        idle.dispose();
        runF.dispose();
        runR.dispose();
        runL.dispose();
        runB.dispose();
        death.dispose();
        dead.dispose();
        wave.dispose(world);
    }

    public void update(float deltaTime, btDynamicsWorld world, Camera camera, Enemies enemies, InputPoller input, Audio audio, Overlay overlay) {
        motion.transform.setToTranslation(position);
        //RING OUT!
        if (position.z < -1.0f) {
            //TODO Play Falling sound
            hit(audio);
            //TODO Show game over screen
            overlay.gameOver = true;
        } else if (velocity.z >= 0.0f) {
            position.z = height/2f;
        }

        if (alive) {
            yaw -= input.deltaX * 0.1f;
            direction.set(input.strafingAxis, input.movementAxis, 0f);
            direction.rotate(Vector3.Z, yaw);
            if (direction.len2() > 1f) direction.nor();
        } else {
            direction.setZero();
        }

        Movement.move(deltaTime, world, body, shape, position, velocity, direction, speed, motion);

        //Update camera
        if (alive) {
            float add = Math.min(1f, deltaTime * 10.0f);
            float cur = 1f - add;
            cameraPosition.scl(cur);
            cameraPosition.mulAdd(position, add);

            camera.direction.set(0f, 1f, -0.4f);
            camera.direction.nor();
            camera.direction.rotate(Vector3.Z, yaw);

            camera.position.set(0f, -1.5f, 1.0f);
            camera.position.rotate(Vector3.Z, yaw);
            camera.position.add(cameraPosition);

            camera.yaw = yaw;
        }

        {
            float add = Math.min(1f, deltaTime * 5.0f);
            float cur = 1f - add;
            waterBallPosition.scl(cur);
            waterBallPosition.mulAdd(position, add);

            waterBall.transform.setToTranslation(waterBallPosition);
            waterBall.transform.translate(camera.direction);
            waterBall.transform.translate(camera.direction);
            waterBall.transform.translate(0f, 0f, 1f);
            waterBall.transform.rotate(Vector3.Z, yaw);
            waterBall.transform.scale(armed, armed, armed);
        }

        //Update animations
        if (velocity.len2() > 0.3f || direction.len2() > 0.1f) {

            float cameraDirection = ((MathUtils.atan2(camera.direction.x, camera.direction.y) * MathUtils.radiansToDegrees) + 360) % 360;
            float forwardDirection = ((MathUtils.atan2(direction.x, direction.y) * MathUtils.radiansToDegrees) + 360) % 360;

            float angleDelta = cameraDirection - forwardDirection;

            if(angleDelta<-180) angleDelta+=360f;
            if(angleDelta>=180) angleDelta-=360f;

            if (angleDelta > -60 && angleDelta < 60) currentAnimation = runF;
            else if (angleDelta > -120 && angleDelta < 0) currentAnimation = runR;
            else if (angleDelta > 0 && angleDelta < 120) currentAnimation = runL;
            else currentAnimation = runB;



            walkSoundsTime += deltaTime;
            walkSoundsTime %= walkSoundsDelta;
            if (alive && walkSoundsTime + deltaTime > walkSoundsDelta) {
                audio.playSound(SoundType.PLAYER_FOOTSTEP, position, direction, position);
            }
        } else if (!alive) {
            currentAnimation = death;
            if (death.currentTime + deltaTime > death.totalTime) {
                currentAnimation = dead;
            }

            // Set Overlay
            overlay.gameOver = true;
        } else {
            currentAnimation = idle;
        }

        // Reset Animations
        if (alive) {
            death.resetAnimation();
            dead.resetAnimation();
        } else {
            runF.resetAnimation();
            runR.resetAnimation();
            runL.resetAnimation();
            runB.resetAnimation();
            idle.resetAnimation();
        }

        currentAnimation.update(deltaTime);

        model.transform.setToTranslation(position);
        model.transform.rotate(Vector3.Z, yaw);
        for (Material m: model.materials) {
            TextureAttribute t = (TextureAttribute) m.get(TextureAttribute.Diffuse);
            t.textureDescription.texture = currentAnimation.currentFrame;
            m.set(t);
        }
        shadow.transform.setToTranslation(position);
        shadow.transform.translate(0f, 0f, -height/2f + 0.01f);
        shadow.transform.rotate(Vector3.X, -90f);

        //Shooting
        if (! alive) {
            armed -= deltaTime;
            if (armed < 0f) armed = 0f;
        } else if (armed < 1f) {
            armed -= deltaTime;
            if (armed < 0) armed = 0f;
        } else if (input.fire) {
            armed = 0f;
            wave.spawn(position, yaw);
            audio.playSound(SoundType.PLAYER_GRUNT, position, direction, position);
            audio.playSound(SoundType.PLAYER_WATERTHROW, position, direction, position);
        }

        wave.update(deltaTime, world, enemies, camera, audio);

        if (!openingLinePlayed){
            openingLinePlayed = true;
            audio.pauseMusicAndStopSound(4f); // about longest opening line sound
            audio.playSound(SoundType.OPENING_LINE, position, direction, position, true);
        }
    }

    public void render(ModelBatch batch) {
        wave.render(batch);
        batch.render(model);
        batch.render(shadow);
        batch.render(waterBall);
    }

    public void hit(Audio audio) {
        if (alive == true) { 		
            audio.pauseMusicAndStopSound(5f); //about longest death sound
            audio.playSound(SoundType.PLAYER_DEATH, position, direction, position, true);
        }
        alive = false;
        //TODO Start Death animation
        //TODO Play death sound

    }

    public void jump() {
        // prevent unlimited jump
        if (alive && velocity.z < 0.04f && velocity.z > -0.04f) {
            if (velocity.x <= 0.1f && velocity.y <= 0.1f) {
                // jump on the spot
                velocity = new Vector3(velocity.x, velocity.y, 4f);
            } else {
                // jump while in movement
                velocity = new Vector3(velocity.x, velocity.y, 2.4f);
            }
        }
    }
}