package pp.battleship.client.gui;

import com.jme3.effect.ParticleEmitter;
import com.jme3.effect.ParticleMesh.Type;
import com.jme3.effect.shapes.EmitterSphereShape;
import com.jme3.material.Material;
import com.jme3.math.ColorRGBA;
import com.jme3.math.FastMath;
import com.jme3.math.Vector3f;
import pp.battleship.client.BattleshipApp;

/**
 * Factory class responsible for creating particle effects used in the game.
 * This centralizes the creation of various types of particle emitters.
 */
public class ParticleEffectFactory {
    private static final int COUNT_FACTOR = 1;
    private static final float COUNT_FACTOR_F = 1f;
    private static final boolean POINT_SPRITE = true;
    private static final Type EMITTER_TYPE = POINT_SPRITE ? Type.Point : Type.Triangle;
    
    private final BattleshipApp app;

    ParticleEffectFactory(BattleshipApp app) {
        this.app = app;
    }

    /**
     * Creates a flame particle emitter.
     * 
     * @return a configured flame particle emitter
     */
    ParticleEmitter createFlame() {
        ParticleEmitter flame = new ParticleEmitter("Flame", EMITTER_TYPE, 32 * COUNT_FACTOR);
        flame.setSelectRandomImage(true);
        flame.setStartColor(new ColorRGBA(1f, 0.4f, 0.05f, (1f / COUNT_FACTOR_F)));
        flame.setEndColor(new ColorRGBA(.4f, .22f, .12f, 0f));
        flame.setStartSize(0.1f);
        flame.setEndSize(0.5f);
        flame.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
        flame.setParticlesPerSec(0);
        flame.setGravity(0, -5, 0);
        flame.setLowLife(.4f);
        flame.setHighLife(.5f);
        flame.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 7, 0));
        flame.getParticleInfluencer().setVelocityVariation(1f);
        flame.setImagesX(2);
        flame.setImagesY(2);
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/flame.png"));
        mat.setBoolean("PointSprite", POINT_SPRITE);
        flame.setMaterial(mat);

        return flame;
    }

    /**
     * Creates a flash particle emitter.
     * 
     * @return a configured flash particle emitter
     */
    ParticleEmitter createFlash() {
        ParticleEmitter flash = new ParticleEmitter("Flash", EMITTER_TYPE, 24 * COUNT_FACTOR);
        flash.setSelectRandomImage(true);
        flash.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, 1f / COUNT_FACTOR_F));
        flash.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f));
        flash.setStartSize(.1f);
        flash.setEndSize(0.5f);
        flash.setShape(new EmitterSphereShape(Vector3f.ZERO, .05f));
        flash.setParticlesPerSec(0);
        flash.setGravity(0, 0, 0);
        flash.setLowLife(.2f);
        flash.setHighLife(.2f);
        flash.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 5f, 0));
        flash.getParticleInfluencer().setVelocityVariation(1);
        flash.setImagesX(2);
        flash.setImagesY(2);
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/flash.png"));
        mat.setBoolean("PointSprite", POINT_SPRITE);
        flash.setMaterial(mat);

        return flash;
    }

    /**
     * Creates a round spark particle emitter.
     * 
     * @return a configured round spark particle emitter
     */
    ParticleEmitter createRoundSpark() {
        ParticleEmitter roundSpark = new ParticleEmitter("RoundSpark", EMITTER_TYPE, 20 * COUNT_FACTOR);
        roundSpark.setStartColor(new ColorRGBA(1f, 0.29f, 0.34f, (float) (1.0 / COUNT_FACTOR_F)));
        roundSpark.setEndColor(new ColorRGBA(0, 0, 0, 0.5f / COUNT_FACTOR_F));
        roundSpark.setStartSize(0.2f);
        roundSpark.setEndSize(0.8f);
        roundSpark.setShape(new EmitterSphereShape(Vector3f.ZERO, 1f));
        roundSpark.setParticlesPerSec(0);
        roundSpark.setGravity(0, -.5f, 0);
        roundSpark.setLowLife(1.8f);
        roundSpark.setHighLife(2f);
        roundSpark.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 3, 0));
        roundSpark.getParticleInfluencer().setVelocityVariation(.5f);
        roundSpark.setImagesX(1);
        roundSpark.setImagesY(1);
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/roundspark.png"));
        mat.setBoolean("PointSprite", POINT_SPRITE);
        roundSpark.setMaterial(mat);

        return roundSpark;
    }

    /**
     * Creates a spark particle emitter.
     * 
     * @return a configured spark particle emitter
     */
    ParticleEmitter createSpark() {
        ParticleEmitter spark = new ParticleEmitter("Spark", Type.Triangle, 30 * COUNT_FACTOR);
        spark.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, 1.0f / COUNT_FACTOR_F));
        spark.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f));
        spark.setStartSize(.5f);
        spark.setEndSize(.5f);
        spark.setFacingVelocity(true);
        spark.setParticlesPerSec(0);
        spark.setGravity(0, 5, 0);
        spark.setLowLife(1.1f);
        spark.setHighLife(1.5f);
        spark.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 20, 0));
        spark.getParticleInfluencer().setVelocityVariation(1);
        spark.setImagesX(1);
        spark.setImagesY(1);
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/spark.png"));
        spark.setMaterial(mat);

        return spark;
    }

    /**
     * Creates a smoke trail particle emitter.
     * 
     * @return a configured smoke trail particle emitter
     */
    ParticleEmitter createSmokeTrail() {
        ParticleEmitter smokeTrail = new ParticleEmitter("SmokeTrail", Type.Triangle, 22 * COUNT_FACTOR);
        smokeTrail.setStartColor(new ColorRGBA(1f, 0.8f, 0.36f, 1.0f / COUNT_FACTOR_F));
        smokeTrail.setEndColor(new ColorRGBA(1f, 0.8f, 0.36f, 0f));
        smokeTrail.setStartSize(.2f);
        smokeTrail.setEndSize(1f);
        smokeTrail.setFacingVelocity(true);
        smokeTrail.setParticlesPerSec(0);
        smokeTrail.setGravity(0, 1, 0);
        smokeTrail.setLowLife(.4f);
        smokeTrail.setHighLife(.5f);
        smokeTrail.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 12, 0));
        smokeTrail.getParticleInfluencer().setVelocityVariation(1);
        smokeTrail.setImagesX(1);
        smokeTrail.setImagesY(3);
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/smoketrail.png"));
        smokeTrail.setMaterial(mat);

        return smokeTrail;
    }

    /**
     * Creates a debris particle emitter.
     * 
     * @return a configured debris particle emitter
     */
    ParticleEmitter createDebris() {
        ParticleEmitter debris = new ParticleEmitter("Debris", Type.Triangle, 15 * COUNT_FACTOR);
        debris.setSelectRandomImage(true);
        debris.setRandomAngle(true);
        debris.setRotateSpeed(FastMath.TWO_PI * 4);
        debris.setStartColor(new ColorRGBA(1f, 0.59f, 0.28f, 1.0f / COUNT_FACTOR_F));
        debris.setEndColor(new ColorRGBA(.5f, 0.5f, 0.5f, 0f));
        debris.setStartSize(.10f);
        debris.setEndSize(.15f);
        debris.setParticlesPerSec(0);
        debris.setGravity(0, 12f, 0);
        debris.setLowLife(1.4f);
        debris.setHighLife(1.5f);
        debris.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 15, 0));
        debris.getParticleInfluencer().setVelocityVariation(.60f);
        debris.setImagesX(3);
        debris.setImagesY(3);
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/Debris.png"));
        debris.setMaterial(mat);

        return debris;
    }

    /**
     * Creates a shockwave particle emitter.
     * 
     * @return a configured shockwave particle emitter
     */
    ParticleEmitter createShockwave() {
        ParticleEmitter shockwave = new ParticleEmitter("Shockwave", Type.Triangle, 1 * COUNT_FACTOR);
        shockwave.setFaceNormal(Vector3f.UNIT_Y);
        shockwave.setStartColor(new ColorRGBA(.48f, 0.17f, 0.01f, .8f / COUNT_FACTOR_F));
        shockwave.setEndColor(new ColorRGBA(.48f, 0.17f, 0.01f, 0f));
        shockwave.setStartSize(0f);
        shockwave.setEndSize(3f);
        shockwave.setParticlesPerSec(0);
        shockwave.setGravity(0, 0, 0);
        shockwave.setLowLife(0.5f);
        shockwave.setHighLife(0.5f);
        shockwave.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 0, 0));
        shockwave.getParticleInfluencer().setVelocityVariation(0f);
        shockwave.setImagesX(1);
        shockwave.setImagesY(1);
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Explosion/shockwave.png"));
        shockwave.setMaterial(mat);

        return shockwave;
    }

    /**
     * Creates a moving smoke emitter.
     * 
     * @return a configured smoke emitter
     */
    ParticleEmitter createMovingSmokeEmitter() {
        ParticleEmitter smokeEmitter = new ParticleEmitter("SmokeEmitter", Type.Triangle, 300);
        smokeEmitter.setGravity(0, 0, 0);
        smokeEmitter.getParticleInfluencer().setVelocityVariation(1);
        smokeEmitter.setLowLife(1);
        smokeEmitter.setHighLife(1);
        smokeEmitter.getParticleInfluencer().setInitialVelocity(new Vector3f(0, .5f, 0));
        smokeEmitter.setImagesX(15); // Assuming the smoke texture is a sprite sheet with 15 frames
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Smoke/Smoke.png"));
        smokeEmitter.setMaterial(mat);

        return smokeEmitter;
    }

    /**
     * Creates a one-time water splash particle emitter.
     * 
     * @return a configured one-time water splash particle emitter
     */
    public ParticleEmitter createWaterSplash() {
        // Create a new particle emitter for the splash effect
        ParticleEmitter waterSplash = new ParticleEmitter("WaterSplash", Type.Triangle, 30);
        
        // Set the shape of the emitter, making particles emit from a point or small area
        waterSplash.setShape(new EmitterSphereShape(Vector3f.ZERO, 0.2f));
        
        // Start and end colors for water (blue, fading out)
        waterSplash.setStartColor(new ColorRGBA(0.4f, 0.4f, 1f, 1f));  // Light blue at start
        waterSplash.setEndColor(new ColorRGBA(0.4f, 0.4f, 1f, 0f));    // Transparent at the end
        
        // Particle size: small at start, larger before fading out
        waterSplash.setStartSize(0.1f);
        waterSplash.setEndSize(0.3f);

        // Particle lifespan (how long particles live)
        waterSplash.setLowLife(0.5f);
        waterSplash.setHighLife(1f);

        // Gravity: Pull the water particles downwards
        waterSplash.setGravity(0, -9.81f, 0);  // Earth's gravity simulation
        
        // Velocity: Give particles an initial burst upward (simulates splash)
        waterSplash.getParticleInfluencer().setInitialVelocity(new Vector3f(0, 3, 0));
        waterSplash.getParticleInfluencer().setVelocityVariation(0.6f);  // Add randomness to splash
        
        // Set how many particles are emitted per second (0 to emit all particles at once)
        waterSplash.setParticlesPerSec(0);
        
        // Load a texture for the water splash (assuming a texture exists at this path)
        Material mat = new Material(app.getAssetManager(), "Common/MatDefs/Misc/Particle.j3md");
        mat.setTexture("Texture", app.getAssetManager().loadTexture("Effects/Splash/splash.png"));
        waterSplash.setMaterial(mat);

        return waterSplash;
    }
}
