using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace MojaDrugaGra;

public class Game1 : Game
{
    private GraphicsDeviceManager _graphics;
    //private SpriteBatch _spriteBatch;

    public Game1()
    {
        _graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
        IsMouseVisible = true;

        _graphics.GraphicsProfile = GraphicsProfile.Reach;
    }

    private BasicEffect efekt;
    private Prostopadloscian prostopadloscian, podloze, cienProstopadloscianu;

    protected override void Initialize()
    {
        // TODO: Add your initialization logic here
        efekt = new BasicEffect(_graphics.GraphicsDevice);
        efekt.VertexColorEnabled = true;
        efekt.Projection = Matrix.CreatePerspective(
            2.0f * _graphics.GraphicsDevice.Viewport.AspectRatio,
            2.0f, 1.0f, 10.0f);
        efekt.View = Matrix.CreateLookAt(
            new Vector3(0, 0, 2.5f),
            new Vector3(0, 0, 0),
            new Vector3(0, 1, 0));
        efekt.World = Matrix.Identity;

        //efekt.EnableDefaultLighting();
        //efekt.AmbientLightColor = Color.DarkGray.ToVector3();

        efekt.EnableDefaultLighting();
         efekt.AmbientLightColor = Color.Gray.ToVector3();

         //cialo doskonale czarne
         efekt.AmbientLightColor = Color.Black.ToVector3();
         efekt.DiffuseColor = Color.Black.ToVector3();
         efekt.SpecularColor = Color.Black.ToVector3();
         efekt.EmissiveColor = Color.Black.ToVector3();

         //zrodla swiatla
         efekt.DirectionalLight0.DiffuseColor = Color.White.ToVector3();
         efekt.DirectionalLight0.SpecularColor = Color.Gray.ToVector3();

        efekt.SpecularColor = Color.White.ToVector3();
        efekt.SpecularPower = 16;
        efekt.DiffuseColor = Color.White.ToVector3();
        efekt.AmbientLightColor = Color.Gray.ToVector3();
        efekt.EmissiveColor = Color.White.ToVector3();

        prostopadloscian = new Prostopadloscian(
            //this, efekt, 1.5f, 1.0f, 2.0f, Color.White);
            this, efekt, 1.5f, 1.5f, 1.5f, Color.White);
        this.Components.Add(prostopadloscian);        

        //podłoże
        podloze = new Prostopadloscian(this, efekt, 10f, 0.1f, 10f, Color.Green);
        podloze.MacierzSwiata=Matrix.CreateScale(0.75f) * Matrix.CreateTranslation(0, -2, 0);
        this.Components.Add(podloze);

        //cien
        BasicEffect efektCienia = (BasicEffect)efekt.Clone();
        efektCienia.DiffuseColor = Color.Black.ToVector3();
        efektCienia.SpecularColor = Color.Black.ToVector3();
        efektCienia.EmissiveColor = Color.White.ToVector3();

        cienProstopadloscianu = new Prostopadloscian(
            this, efektCienia, 1.5f, 1.5f, 1.5f, Color.DarkGreen);
        this.Components.Add(cienProstopadloscianu);

        base.Initialize();
    }

    static Matrix CreateShadowMatrix(Vector3 lightPosition, Plane plane,
                                     bool infinitelyDistantLightSource = true)
    {
        Vector4 N = new Vector4(plane.Normal, plane.D);
        Vector4 L = new Vector4(lightPosition,
        infinitelyDistantLightSource ? 0 : 1);
        float correction = infinitelyDistantLightSource ? 0.00001f : 0;
        float alfa = Vector4.Dot(N, L);
        Matrix m = new Matrix();
        m.M11 = alfa - N.X * L.X;
        m.M22 = alfa - N.Y * L.Y;
        m.M33 = alfa - N.Z * L.Z;
        m.M44 = alfa - N.W * L.W;
        m.M21 = -N.Y * L.X;
        m.M31 = -N.Z * L.X;
        m.M41 = -N.W * L.X;
        m.M12 = -N.X * L.Y;
        m.M32 = -N.Z * L.Y;
        m.M42 = -N.W * L.Y;
        m.M13 = -N.X * L.Z;
        m.M23 = -N.Y * L.Z;
        m.M43 = -N.W * L.Z;
        m.M14 = -N.X * L.W;
        m.M24 = -N.Y * L.W + correction;
        m.M34 = -N.Z * L.W;
        return m;
    }

    const float d = 2 - 0.05f;
    Vector3 polożenieŹródłaŚwiatła = new Vector3(3, 5, 3);
    bool rzutowanieRównoległe = false;

    Matrix macierzRzutowaniaNaPodłoże
    {
        get
        {
            return CreateShadowMatrix(
                polożenieŹródłaŚwiatła,
                new Plane(Vector3.Up, d),
                rzutowanieRównoległe);
        }
    }

    protected override void LoadContent()
    {
        //_spriteBatch = new SpriteBatch(GraphicsDevice);

        //Texture2D tekstura = Content.Load<Texture2D>("Lena");
        //Texture2D tekstura = Content.Load<Texture2D>("wooden_box");
        /*
        Texture2D tekstura = Content.Load<Texture2D>("box");
        if (tekstura != null)
        {
            prostopadloscian.Tekstura = tekstura;
            prostopadloscian.TeksturowanieWłączone = true;
        }
        */
        Texture2D tekstura = Content.Load<Texture2D>("box");
        int liczbaPikseli = tekstura.Width * tekstura.Height;
        Color[] tabelaPikseli = new Color[liczbaPikseli];
        tekstura.GetData<Color>(tabelaPikseli);
            
        for (int i = 0; i < liczbaPikseli; i++)
        {
            if (tabelaPikseli[i] == Color.Black)
                tabelaPikseli[i] = Color.Transparent;
        }
        tekstura.SetData<Color>(tabelaPikseli);
        if (tekstura != null)
        {
            prostopadloscian.Tekstura = tekstura;
            prostopadloscian.TeksturowanieWłączone = true;
        }
    }

    protected override void Update(GameTime gameTime)
    {
        KeyboardState stanKlawiatury = Keyboard.GetState();
        GamePadState stanGamepada = GamePad.GetState(PlayerIndex.One);

        if (stanGamepada.Buttons.Back == ButtonState.Pressed || stanKlawiatury.IsKeyDown(Keys.Escape))
            Exit();

        // TODO: Add your update logic here
        float katObrotu = 0.01f;        
        if (stanKlawiatury.IsKeyDown(Keys.LeftShift) || stanKlawiatury.IsKeyDown(Keys.RightShift))
            katObrotu *= 10;

        if (stanKlawiatury.IsKeyDown(Keys.Left) || stanGamepada.IsButtonDown(Buttons.DPadLeft))
            prostopadloscian.MacierzSwiata *= Matrix.CreateRotationY(katObrotu);
        if (stanKlawiatury.IsKeyDown(Keys.Right) || stanGamepada.IsButtonDown(Buttons.DPadRight))
            prostopadloscian.MacierzSwiata *= Matrix.CreateRotationY(-katObrotu);
        if (stanKlawiatury.IsKeyDown(Keys.Up) || stanGamepada.IsButtonDown(Buttons.DPadUp))
            prostopadloscian.MacierzSwiata *= Matrix.CreateRotationX(katObrotu);
        if (stanKlawiatury.IsKeyDown(Keys.Down) || stanGamepada.IsButtonDown(Buttons.DPadDown))
            prostopadloscian.MacierzSwiata *= Matrix.CreateRotationX(-katObrotu);
        if (stanKlawiatury.IsKeyDown(Keys.OemPeriod))
            prostopadloscian.MacierzSwiata *= Matrix.CreateRotationZ(katObrotu);
        if (stanKlawiatury.IsKeyDown(Keys.OemComma))
            prostopadloscian.MacierzSwiata *= Matrix.CreateRotationZ(-katObrotu);        

        Vector2 wychylenieLewegoGrzybka = stanGamepada.ThumbSticks.Left;
        prostopadloscian.MacierzSwiata *= Matrix.CreateRotationY(katObrotu * wychylenieLewegoGrzybka.X);
        prostopadloscian.MacierzSwiata *= Matrix.CreateRotationX(-katObrotu * wychylenieLewegoGrzybka.Y);

        Vector2 wychyleniePrawegoGrzybka = stanGamepada.ThumbSticks.Right;
        prostopadloscian.MacierzSwiata *= Matrix.CreateRotationY(10 * katObrotu * wychyleniePrawegoGrzybka.X);
        prostopadloscian.MacierzSwiata *= Matrix.CreateRotationX(-10 * katObrotu * wychyleniePrawegoGrzybka.Y);
        
        cienProstopadloscianu.MacierzWidoku = efekt.View;
        cienProstopadloscianu.MacierzSwiata = 
            prostopadloscian.MacierzSwiata * macierzRzutowaniaNaPodłoże;

        base.Update(gameTime);
    }

    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.Black);

        // TODO: Add your drawing code here

        base.Draw(gameTime);
    }
}
