"use strict";

const MEADOW_SCROLL_SPEED=1;
const MEADOW_NUM_FLOWERS = 20;
const MEADOW_FLOWER_FACTS = {
    flower1: {y:-10, width:15},
    flower2: {y:0, width: 10},
    flower3: {y:1, width: 20},
    flower4: {y:8, width: 12},
    flower5: {y: 8, width: 12},
    flower6: {y: 0, width: 15}
}



class MeadowScene extends BaseScene {
    _flowers = [];
    _leafs = [];
    _beeSwarms = []; // Tiny, tiny swarms
    _treeScrollOffset = 0;
    _beeAnimation = new Animation();
    _eye = {};

    // Load resources here
    load(loadingContext) {
        const ctx = loadingContext;
        ctx.loadShader("sunnySky", "fullscreen.vert", "sunnySky.frag");
        
        for (let i=1; i<=6; ++i) {
            ctx.loadSprite(`flower${i}`, `flower${i}.png`);
        }

        ctx.loadSprite("tree", "tree.png");
        ctx.loadSprite("leaf", "leaf.png");

        for (let i = 1; i <= 3; i++) {
            const name = `bee${i}`;
            ctx.loadSprite(name,`${name}.png`);
            this._beeAnimation.addSprite(name);
        }

        ctx.loadSprite("eyeBack", "eyeBack.png");
        ctx.loadSprite("eyeFront", "eyeFront.png");
        ctx.loadSprite("eyePupil", "eyePupil.png");
    }

    // One-time initialization at start of scene
    initialize() {
        for (let flowerId = 0; flowerId < MEADOW_NUM_FLOWERS; ++flowerId) {
            this._flowers.push(this._makeFlower(flowerId, 240));
        }

        const centerX = 120;
        const centerY = 70;
        this._leafs.push(this._createLeafGroup(centerX + 16, centerY + 10, 14, 128));
        this._leafs.push(this._createLeafGroup(centerX - 14, centerY + 3, 13, 128));
        this._leafs.push(this._createLeafGroup(centerX, centerY-20, 30, 768));

        for (let i = 0; i < 6; i++) {
            this._beeSwarms.push(this._createSwarm());
        }

        this._beeAnimation.sequence = [0,1,2,1,0];

        this._eye = this._createEye();
    }

    _createEye = function() {
        return {
            x: 300,
            y: 130,
            speed: -1.5,
        }
    }

    _updateEye = function() {
        this._eye.x += this._eye.speed;
        if (this._eye.x < -50 || this._eye > 290)
            this._eye.speed = -this._eye.speed;
    }

    // This is where the magic happens
    update(renderContext, time) {
        const ctx = renderContext;
        ctx.backgroundShader("sunnySky", {
            cloudSpeed: 1.5, 
            horizonAngle: this._clamp(- 0.1 + time / 6, -0.1, 0.03)
        });

        const timeForSomeFlowers = 4;
        const timeForSomeBees = 8;
        const timeForSomeEyeballs = 16;

        if (time > timeForSomeFlowers)
        {
            // Scrolling flowers
            this._flowers.forEach((flower) => {
                ctx.sprite(flower.sprite,flower.x,78+flower.y,flower.width);
                flower.x -= MEADOW_SCROLL_SPEED;
            })

            for (let flowerId=0; flowerId<MEADOW_NUM_FLOWERS; ++flowerId) {
                if (this._flowers[flowerId].x < -20) {
                    this._flowers[flowerId] = this._makeFlower(MEADOW_NUM_FLOWERS, 0);
                }
            }
        }

        
        // Bees
        if (time > timeForSomeBees) {
            for (let swarmIndex = 0; swarmIndex < this._beeSwarms.length; swarmIndex++) {
                const swarm = this._beeSwarms[swarmIndex];
                for (const bee of swarm) {
                    const beeSprite = this._beeAnimation.getSprite(2 * time);
                    ctx.sprite(beeSprite, bee.x, bee.y, 10);
                }
                this._updateSwarm(swarmIndex);
            }
        }

        // Flowering tree
        if (time > timeForSomeFlowers + 3)
            this._treeScrollOffset -= 0.7 * MEADOW_SCROLL_SPEED;

        this._clamp(time / MEADOW_SCROLL_SPEED - timeForSomeFlowers, 0, 10000);
        if (true || this._treeScrollOffset > -200) {
            ctx.sprite("tree", 120 + this._treeScrollOffset, 70, 60);
            let animationPos = 0.5 * time - 1;
            if (animationPos < 0) animationPos = 0;
            if (animationPos > 1) animationPos = 1;
            const rotationPos = animationPos;
            
            for (const leafGroup of this._leafs) {
                for (const leaf of leafGroup) {
                    const item = new SpriteItem();
                    item.width = 3;
                    item.name = "leaf";
                    item.position.x = 
                        this._treeScrollOffset + 
                        this._lerp(leaf.originX, leaf.targetX, animationPos) +
                        -25 + 25 * Math.cos(rotationPos * 2 * Math.PI)
                    item.position.y = 
                        this._lerp(leaf.originY, leaf.targetY, animationPos) +
                        25 * Math.sin(rotationPos * 2 * Math.PI)
                    item.rotation = leaf.rotation;
                    ctx.sprite(item);                
                }
            }
        }

        // Eyeball
        if (time > timeForSomeEyeballs) {
            this._updateEye(this._eye);
            const eyeX = this._eye.x;
            const eyeY = 105 - 20 * Math.abs(Math.sin(time * 5))
            ctx.sprite("eyeBack", eyeX, eyeY, 25);
            ctx.sprite("eyePupil", eyeX, eyeY + 6 - 12 * Math.abs(Math.sin(time * 5 - 0.2)), 12);
            ctx.sprite("eyeFront", eyeX, eyeY, 25);
        }
    }

    _makeFlower(flowerPos, offset) {
        const sprite = `flower${Math.floor(Math.random()*6)+1}`;
        const sizeRandom = (0.5 + 0.5*Math.random());
        return {
            x: offset + flowerPos*240/MEADOW_NUM_FLOWERS+Math.random()*4,
            y: MEADOW_FLOWER_FACTS[sprite].y-sizeRandom/2,
            width: MEADOW_FLOWER_FACTS[sprite].width* sizeRandom,
            sprite
        }
    }

    _createSwarm() {
        const swarm = [];

        const selector = 10 * Math.random();
        const numBees =
            selector > 8 ? 5 :
            selector > 7 ? 4 :
            selector > 6 ? 3 :
            selector > 4 ? 2 :
            1;
        
        const swarmX = -10 - 50 * Math.random();
        const swarmSpeed = 0.5 + 2 * Math.random();
        const swarmY = 10 + 60 * Math.random();
        const swarmRadius = 6 + 2 * numBees * Math.random();
        for (let i = 0; i < numBees; i++)
        {
            const angle = i * 2 * Math.PI / numBees;
            const rx = -2 + 4 * Math.random();
            const ry = -2 + 3 * Math.random();
            swarm.push({
                x: swarmX + rx + swarmRadius * Math.cos(angle),
                y: swarmY + ry + 0.6 * swarmRadius * Math.sin(angle),
                speed: swarmSpeed,
                animOffset: Math.floor(3 * Math.random()),
            });
        }

        return swarm;
    }

    _updateSwarm(swarmIndex) {
        const swarm = this._beeSwarms[swarmIndex];

        let respawn = false;
        for (const bee of swarm) {
            bee.x += bee.speed;

            if (bee.x > 280) {
                respawn = true;
            }
        }

        if (respawn) 
            this._beeSwarms[swarmIndex] = this._createSwarm();
    }

    _createLeafGroup(centerX, centerY, radius, amount) {
        const leafs = [];        
        for (let i = 0; i < amount; i++) {
            const origin = this._randomPointOnCircle(160, 170);
            const target = this._randomPointOnCircle(0, radius);

            leafs.push({
                originX: centerX + origin.x,
                originY: centerY + origin.y,
                targetX: centerX + target.x,
                targetY: centerY + target.y,
                rotation: 360 * Math.random()
            })
        }
        return leafs;
    }

    _randomPointOnCircle(minRadius, maxRadius) {
        const r = minRadius + (maxRadius - minRadius) * Math.sqrt(Math.random())
        const theta = Math.random() * 2 * Math.PI;

        return {
            x: r * Math.cos(theta),
            y: r * Math.sin(theta)
        }
    }

    _lerp(a, b, t) {
        if (t < 0) t = 0;
        if (t > 1) t = 1;
        return a + t * (b - a);
    }
}