<script lang="ts">
import '$lib/utils/pixiInit'; // Initialize PixiJS settings before importing filters
import * as PIXI from 'pixi.js';
import * as filters from 'pixi-filters';
import gsap from 'gsap';
import { ScrollTrigger } from 'gsap/ScrollTrigger';
import { SplitText } from 'gsap/SplitText';
import { PixiPlugin } from "gsap/PixiPlugin";
import { onMount, onDestroy } from 'svelte';
import { browser } from '$app/environment';
import createCanvasText from '$lib/utils/createCanvasText';
import createCanvasImg from '$lib/utils/createCanvasImg';
import { tick } from 'svelte';

let { 
	textsToCanvas = [],
	imgsToCanvas = []
}: {
	textsToCanvas?: Array<HTMLElement>;
	imgsToCanvas?: Array<HTMLElement>;
} = $props();
let app: PIXI.Application;
let canvas: HTMLCanvasElement;

onMount(()=>{
  let cleanup: (() => void) | undefined;
  
  (async ()=>{

  function xFrac(x: number){
    return window.innerWidth * x;
  }
  function yFrac(y: number){
    return window.innerHeight * y;
  }

    let is_fine = window.matchMedia('(pointer:fine)').matches
    let is_coarse = window.matchMedia('(pointer:coarse)').matches
    let is_landscape = window.matchMedia('(orientation:landscape)').matches
    let is_portrait = window.matchMedia('(orientation:portrait)').matches
    let is_twisted = false;

    gsap.registerPlugin(PixiPlugin, ScrollTrigger, SplitText);
    
    app = new PIXI.Application();
    await app.init({
      canvas: canvas,
      resizeTo: window,
      antialias: true,
      autoDensity: true, 
      resolution: 2,
      backgroundAlpha: 0,
    });
    
      //for debugging but Typescript has an issue with this:
    (globalThis as any).__PIXI_APP__ = app;
    
    PixiPlugin.registerPIXI(PIXI);
  
    let bulgegroup = new PIXI.Container();
    bulgegroup.pivot.set(xFrac(0.5), yFrac(0.5));
    bulgegroup.x = xFrac(0.5);
    bulgegroup.y = yFrac(0.5);
    app.stage.addChild(bulgegroup);
    
    let bulgebg = new PIXI.Graphics();
    bulgebg.rect(0, 0, xFrac(1), yFrac(1));
    bulgebg.fill('rgb(0, 0, 0)');
    bulgebg.alpha = 0;
    bulgebg.pivot.set(xFrac(.5), yFrac(.5));
    bulgebg.x = xFrac(0.5);
    bulgebg.y = yFrac(0.5);
    bulgegroup.addChild(bulgebg);
    
    let center = [0.5, 0.5];
    
    let bulgefilter = new filters.BulgePinchFilter();
    bulgefilter.radius = is_landscape ? xFrac(0.5) : xFrac(0.55);
    bulgefilter.strength = 0.5;
    bulgefilter.center = is_landscape ? center : [0.5, 0];
    bulgefilter.resolution = 2;

    let twistfilter = new filters.TwistFilter();
    twistfilter.angle = 0;
    twistfilter.radius = is_landscape ? window.innerWidth/4 : window.innerWidth/2;
    twistfilter.offset = new PIXI.Point(window.innerWidth/2, window.innerHeight/3);
    twistfilter.resolution = 2;

    bulgegroup.filters = [(bulgefilter as unknown as PIXI.Filter), (twistfilter as unknown as PIXI.Filter)];

    gsap.to(twistfilter, {
      angle: -1.33,
      duration: 1,
      ease: 'elastic.out(2, 0.4)',
      delay: 2,
      onComplete: () => {
        is_twisted = true;
      }
    })


    /*----------------------------------
    * Convert text to canvas using 
    * createCanvasText function
    ----------------------------------*/    
    let canvasTexts: Array<PIXI.Text> = [];
    let elems: Array<HTMLElement> = [];
    
    async function convertText(){
      await tick();
      textsToCanvas.forEach((element) => {
        elems.push(element);
        let canvasText = createCanvasText(element, bulgegroup);
        canvasTexts.push(canvasText);
      })
    }  
  
    /*----------------------------------
     * Function to update text on canvas
     * runs in the Ticker
     ----------------------------------*/
    function updateText(){
      canvasTexts.forEach((text, index) => {
        let headlinePosition = elems[index].getBoundingClientRect();
        headlinePosition.x = headlinePosition.x ;
        headlinePosition.y = headlinePosition.y ; 
        text.position.set(headlinePosition.x, headlinePosition.y);
        text.alpha = elems[index].style.opacity as unknown as number;
        text.style.fill = window.getComputedStyle(elems[index]).color;
      })
    }
  
    /*----------------------------------
     * Convert images to canvas
     * createCanvacImgs function
     ----------------------------------*/
    let canvasImgs: Array<PIXI.Sprite> = [];
    let imgElems: Array<HTMLElement> = [];
    
    function convertImgs(){
      imgsToCanvas.forEach((element) => {
        imgElems.push(element);
        let canvasImg = createCanvasImg(element as HTMLImageElement, app.stage);
        canvasImgs.push(canvasImg);
      })
    }
  
    setTimeout(() => {
      convertImgs();
      convertText();
    }, 100);
  
    /*----------------------------------
     * Function to update text on canvas
     * runs in the Ticker
     ----------------------------------*/
     function updateImgs(){
      canvasImgs.forEach((image, index) => {
        let imagePosition = imgElems[index].getBoundingClientRect();
        imagePosition.x = imagePosition.x + xFrac(0.1);
        imagePosition.y = imagePosition.y + yFrac(0.1);
        image.position.set(imagePosition.x, imagePosition.y);
        image.width = imagePosition.width;
        image.height = imagePosition.height;
      })
    }
  
    /*----------------------------------
    * Mousemove events
    *----------------------------------*/
    let tween = {
      x: 0.5,
      y: is_fine ? 0.5 : 250/window.innerHeight,
    };
    const mouse = {
      x: xFrac(0.5),
      y: yFrac(0.5),
    }
    
    if (is_fine) {
      window.addEventListener('mousemove', (e) => {
        const pointerX = e.clientX / window.innerWidth;
        const pointerY = e.clientY / window.innerHeight;
        const pointerXfrac = pointerX - 0.5;
        const pointerYfrac = pointerY - 0.5;
        
        if (is_twisted){
          gsap.to(mouse, {
            duration: 0.5,
            ease: 'power3.out',
            overwrite: true,
            x: e.clientX,
            y: e.clientY,
          })
        }

        gsap.to(tween, {
          duration: .5,
          ease: 'power3.out',
          overwrite: true,
          x: 0.5 + pointerXfrac/2,
          y: 0.5 + pointerYfrac/6,
        })
      }, { passive: true })
    }
  
  
    /*----------------------------------
    * The Ticker
    * ----------------------------------*/  
    let elapsed = 0.0;
  
    app.ticker.add((ticker) => {
      elapsed += ticker.deltaTime;
      if (!is_landscape) {
        // bulgefilter.center = [(tween.x + Math.sin(elapsed/200)/20 ),(tween.y + Math.cos(elapsed/200)/20 )];
        let movingCenter = [(0.5 + Math.sin(elapsed/200)/20 ),(0.33 + Math.cos(elapsed/200)/20 )];
        bulgefilter.center = movingCenter;
        twistfilter.offset = new PIXI.Point( 
          window.innerWidth * movingCenter[0] , 
          window.innerHeight * movingCenter[1]
        );
        // bulgefilter.center = [0.5, 0.25];
      } else {
        bulgefilter.center = [tween.x, tween.y];
        is_twisted ? twistfilter.offset = new PIXI.Point(mouse.x, window.innerHeight/3) : null;
      }
      updateImgs();
      updateText();
    })

    window.addEventListener('resize', (e) => {
      tween.y = is_fine ? 0.5 : 250/window.innerHeight;
    })
    
    cleanup = () => {
      gsap.killTweensOf(imgElems);
      gsap.killTweensOf(elems);
      ScrollTrigger.getAll().forEach( instance => instance.kill() );
    }
  })();
  
  return () => {
    if (cleanup) cleanup();
  }
}) // <- end onMount

onDestroy(() => {
  if (browser){
    app.destroy(true, true);
  }
}) // <- end onDestroy

</script>

<canvas bind:this={canvas}></canvas>

<style>
  canvas {
    position: fixed;
    top: 0;
    left: 0;
    width: 100vw;
    height: 100vh;
    z-index: -1;
  }
</style>