// Another possible inspiration: https://www.khanacademy.org/computer-programming/twinkle-twinkle/6280832014565376
let sketch = function(p) {
  let svgExport = false; // To export the result to SVG

  let bgCol = hexToRgb('#222233');
  let starCol = [hexToRgb('#ffcdff'), hexToRgb('#804442'), hexToRgb('#ffff7d')]

  let starDensity = 0.0005; //0.0005 is safe. Above 0.01 is absurd

  let currentWidth;
  let currentHeight;

  let nbStars;
  let stars;
  let bg;

  let mover;
  let shootingStarDirection;

  let time = 0;

  let sketchLoop = 0;


  p.setup = function(){
    p.frameRate(24);
    currentWidth = p.windowWidth;
    currentHeight = p.windowHeight;

    if (svgExport) {
      p.createCanvas(1920, 1080, p.SVG) // To export the result to SVG
      p.noLoop(); // To export the result to SVG
    } else {
      p.createCanvas(currentWidth, currentHeight);
    }

    bgInit();

    mover = new Mover();
  }

  p.draw = function(){
    // p.background(bgCol);
    p.clear();
    p.image(bg, 0, 0);



    if (time%72 == 0) {  //72 is 3s at 24fps
      if (p.random(1) < 0.3) {
        mover.init();
        let accX = p.random(12, 18) * p.random([-1, 1]);
        let accY = p.random(-4, 4);
        mover.vel.set(accX, accY);
      }
    }

    if (mover.lifespan < 255) {
      mover.update();
      mover.show();
    }


    time += 1;

    if (svgExport) {
        p.save(); // To export the result to SVG
    }
  } //End of draw()

  class Stars {
    //Inspired by https://www.youtube.com/watch?v=NJjEGoqTn1Y
    constructor(nb) {
      this.nb = nb;
      this.x = [];
      this.y = [];
      this.color = [];
      this.size = [];
    }

    make() {
      for (let i = 0; i < this.nb; i++) {
        this.x[i] = p.random(0,p.width);
        this.y[i] = p.random(0,p.height);
        this.color[i] = p.random(starCol);
        this.color[i].setAlpha(p.random(100,230));
        this.size[i] = 1 + p.random(2);
      }
    }

    draw() {
      for (let i = 0; i < this.nb; i++) {
        bg.strokeWeight(this.size[i]);
        bg.stroke(this.color[i]);
        bg.point(this.x[i], this.y[i]);
      }
    }
  }



  class Mover {
    // Simulating Forces
    // The Nature of Code
    // The Coding Train / Daniel Shiffman
    // https://youtu.be/Uibl0UE4VH8
    // https://thecodingtrain.com/learning/nature-of-code/2.1-simulating-forces.html
    // https://editor.p5js.org/codingtrain/sketches/kYWcOmch
    constructor() {
      // this.pos = p.createVector(
      //   p.random(p.round(0.2 * p.width)),
      //   p.random(0, p.round(p.height/2))
      // );
      this.pos = p.createVector(0, 0);
      this.vel = p.createVector(0, 0);
      this.acc = p.createVector(0, 0);
      // this.r = 16;
      this.color = 'white';
      // this.color.setAlpha(p.random(100,230));
      this.size;

      this.lifespan = 255;
      this.burnrate;

    }

    init() {
      this.lifespan = 0;
      this.burnrate = p.random(2, 8);
      //
      this.size = p.random(4,7)
      this.acc.set(0, 0);
      this.vel.set(0, 0);
      this.pos.x = p.random(p.round(0.05 * p.width), p.round(0.95 * p.width));
      this.pos.y = p.random(0, p.round(p.height*0.45));

      let gravity = p.createVector(0, 0.02);
      this.applyForce(gravity);
    }


    applyForce(force) {
      this.acc.set(force);
    }


    edges() {
      if (this.pos.y >= p.height-this.r) {
        this.pos.y = p.height-this.r;
        this.vel.y *= -1;
      }

      if (this.pos.x >= p.width-this.r) {
        this.pos.x = p.width-this.r;
        this.vel.x *= -1;
      } else if (this.pos.x <= this.r) {
        this.pos.x = this.r;
        this.vel.x *= -1;
      }
    }


    update() {

      this.lifespan += this.burnrate;
      this.lifespan = p.constrain(this.lifespan, 0, 255);
      if (this.lifespan < 255) {

        this.pos.add(this.vel);
        this.vel.mult(0.98);
        this.vel.add(this.acc);
      }



    }

    show() {
      p.strokeWeight(this.size);
      // p.stroke(this.color);
      p.stroke(255, p.constrain(305-this.lifespan, 0, 255), 0, 255-0.7*this.lifespan);
      p.point(this.pos);

    }
  }

  p.windowResized = function() {
    let newWidth = p.windowWidth;
    let newHeight = p.windowHeight;
    //Redraw only if new size if bigger than previously
    // if (newWidth > currentWidth || newHeight > currentHeight) {
    if (true) {
      currentWidth = newWidth;
      currentHeight = newHeight;

      p.resizeCanvas(currentWidth, currentHeight);
      bgInit();
    }

  }

  function bgInit() {
    nbStars = calcNumberOfStars();
    bg = p.createGraphics(p.width, p.height);
    // bg.background(bgCol);
    // setGradient(0, 0, p.width, p.height, bgCol, starCol[1]);
    // bg.background(0, 0, 0, 0);

    stars = new Stars(nbStars);
    stars.make();
    stars.draw();
  }

  function calcNumberOfStars() {
    //Helps to get a consistent number of starts regardless the window size
    if (starDensity > 0.01) {
      console.log('starDensity is too high! going back to the maximum (0.01) in order to prevent too much CPU load when starting the patch');
      starDensity = 0.01;
    }
    let nb = p.round(starDensity * currentWidth * currentHeight)
    // console.log('nbStars: ' + nb);
    return nb;
  }

  function hexToRgb(hex) {
    hex = hex.replace('#', '');

    var bigint = parseInt(hex, 16);

    var r = (bigint >> 16) & 255;
    var g = (bigint >> 8) & 255;
    var b = bigint & 255;

    return p.color(r, g, b);
  }
  function setGradient(x, y, w, h, c1, c2) {
    bg.noFill();
    // Top to bottom gradient
    for (let i = y; i <= y + h; i++) {
      let inter = p.pow(p.map(i, y, y + h, 0, 1),6);
      let c = bg.lerpColor(c1, c2, inter);
      bg.stroke(c);
      bg.line(x, i, x + w, i);
    }

  }
};

let processingSketch = new p5(sketch, 'bg');

let processingIsOn = true;
