using System;
using SFML.Graphics;
using SFML.System;
using FluidSim.Components;

namespace FluidSim.Tests
{
    public abstract class Scenario
    {
        public abstract void Initialize(int sampleRate);
        public abstract float Process();
        public abstract void Draw(RenderWindow target);

        protected const double AmbientPressure = 101325.0;
        protected const double AmbientTemperature = 300.0;
        public double Throttle { get; set; } = 0.0;

        // ---------- Color from pressure (volumes) ----------
        protected Color PressureColor(double pressurePa)
        {
            double bar = pressurePa / 1e5;   // convert to bar for easier mapping
            byte r, g, b;

            if (bar < 1.0)   // vacuum → blue to green
            {
                double factor = Math.Clamp(bar, 0.0, 1.0);
                r = 0;
                g = (byte)(255 * factor);
                b = (byte)(255 * (1.0 - factor));
            }
            else   // above ambient → green to red
            {
                double factor = Math.Min((bar - 1.0) / 9.0, 1.0);   // 1→10 bar maps to 0→1
                r = (byte)(255 * factor);
                g = (byte)(255 * (1.0 - factor));
                b = 0;
            }
            return new Color(r, g, b);
        }

        // ---------- Color from temperature (pipes) ----------
        protected Color TemperatureColor(double temperature)
        {
            double t = Math.Clamp(temperature, 0.0, 2000.0);
            byte r, g, b;
            if (t < AmbientTemperature)
            {
                double factor = t / AmbientTemperature;
                r = 0;
                g = (byte)(255 * factor);
                b = (byte)(255 * (1.0 - factor));
            }
            else
            {
                double factor = (t - AmbientTemperature) / (2000.0 - AmbientTemperature);
                r = (byte)(255 * factor);
                g = (byte)(255 * (1.0 - factor));
                b = 0;
            }
            return new Color(r, g, b);
        }

        // ---------- Draw a generic volume (e.g. plenum) ----------
        protected void DrawVolume(RenderWindow target, Volume0D volume,
                                  float centerX, float topY, float width, float height)
        {
            var rect = new RectangleShape(new Vector2f(width, height))
            {
                FillColor = PressureColor(volume.Pressure),   // ← pressure‑based
                Position = new Vector2f(centerX - width / 2f, topY)
            };
            target.Draw(rect);
            var border = new RectangleShape(new Vector2f(width, height))
            {
                FillColor = Color.Transparent,
                OutlineColor = Color.White,
                OutlineThickness = 1f,
                Position = new Vector2f(centerX - width / 2f, topY)
            };
            target.Draw(border);
        }

        // ---------- Draw an engine cylinder ----------
        protected void DrawCylinder(RenderWindow target, Cylinder cylinder,
                                    float centerX, float topY, float width, float maxHeight)
        {
            double fraction = cylinder.PistonFraction;
            float currentHeight = (float)(maxHeight * fraction);

            // Walls
            var wall = new RectangleShape(new Vector2f(width, maxHeight));
            wall.FillColor = new Color(60, 60, 60);
            wall.Position = new Vector2f(centerX - width / 2f, topY);
            target.Draw(wall);

            // Gas – colored by pressure now
            float gasTop = topY;
            var gasRect = new RectangleShape(new Vector2f(width, currentHeight));
            gasRect.FillColor = PressureColor(cylinder.Pressure);   // ← pressure‑based
            gasRect.Position = new Vector2f(centerX - width / 2f, gasTop);
            target.Draw(gasRect);

            // Piston line
            var pistonLine = new RectangleShape(new Vector2f(width, 4f));
            pistonLine.FillColor = Color.White;
            pistonLine.Position = new Vector2f(centerX - width / 2f, topY + currentHeight);
            target.Draw(pistonLine);

            // Valve indicators
            float valveW = 6f, valveH = 10f, valveY = topY + 4f;
            var intakeValve = new RectangleShape(new Vector2f(valveW, valveH));
            intakeValve.FillColor = cylinder.IntakeValveArea > 0 ? Color.Green : Color.Red;
            intakeValve.Position = new Vector2f(centerX - width / 2f - valveW - 2f, valveY);
            target.Draw(intakeValve);

            var exhaustValve = new RectangleShape(new Vector2f(valveW, valveH));
            exhaustValve.FillColor = cylinder.ExhaustValveArea > 0 ? Color.Green : Color.Red;
            exhaustValve.Position = new Vector2f(centerX + width / 2f + 2f, valveY);
            target.Draw(exhaustValve);
        }

        // ---------- Draw a pipe (unchanged) ----------
        protected void DrawPipe(RenderWindow target, Pipe1D pipe, float pipeCenterY, float pipeStartX, float pipeEndX)
        {
            int n = pipe.CellCount;
            if (n < 2) return;

            float pipeLengthPx = pipeEndX - pipeStartX;
            float dx = pipeLengthPx / (n - 1);

            float baseRadius = 25f;
            float rangeFactor = 2f;
            float scaleFactor = 2f;

            static float SmoothStep(float edge0, float edge1, float x)
            {
                float t = Math.Clamp((x - edge0) / (edge1 - edge0), 0f, 1f);
                return t * t * (3f - 2f * t);
            }

            var centers = new float[n];
            var radii = new float[n];
            var temperatures = new double[n];
            double R_gas = 287.0;

            for (int i = 0; i < n; i++)
            {
                double p = pipe.GetCellPressure(i);
                double rho = pipe.GetCellDensity(i);
                double T = p / Math.Max(rho * R_gas, 1e-12);
                temperatures[i] = T;

                float deviation = (float)Math.Tanh((p - AmbientPressure) / AmbientPressure / rangeFactor);
                radii[i] = baseRadius * (1f + deviation * scaleFactor);
                if (radii[i] < 2f) radii[i] = 2f;
                centers[i] = pipeStartX + i * dx;
            }

            int segmentsPerCell = 8;
            int totalPoints = n + (n - 1) * segmentsPerCell;
            Vertex[] stripVertices = new Vertex[totalPoints * 2];
            int idx = 0;

            for (int i = 0; i < n; i++)
            {
                float x = centers[i];
                float r = radii[i];
                Color col = TemperatureColor(temperatures[i]);   // pipes still use temperature

                stripVertices[idx++] = new Vertex(new Vector2f(x, pipeCenterY - r), col);
                stripVertices[idx++] = new Vertex(new Vector2f(x, pipeCenterY + r), col);

                if (i < n - 1)
                {
                    for (int s = 1; s <= segmentsPerCell; s++)
                    {
                        float t = s / (float)segmentsPerCell;
                        float st = SmoothStep(0f, 1f, t);
                        float xi = centers[i] + (centers[i + 1] - centers[i]) * t;
                        float ri = radii[i] + (radii[i + 1] - radii[i]) * st;
                        double Ti = temperatures[i] + (temperatures[i + 1] - temperatures[i]) * st;
                        Color coli = TemperatureColor(Ti);

                        stripVertices[idx++] = new Vertex(new Vector2f(xi, pipeCenterY - ri), coli);
                        stripVertices[idx++] = new Vertex(new Vector2f(xi, pipeCenterY + ri), coli);
                    }
                }
            }

            var pipeMesh = new VertexArray(PrimitiveType.TriangleStrip, (uint)stripVertices.Length);
            for (int i = 0; i < stripVertices.Length; i++)
                pipeMesh[(uint)i] = stripVertices[i];
            target.Draw(pipeMesh);
        }
    }
}