export function registerOcclusionConfig() {
  Hooks.once('canvasReady', () => {
    game.occlusionSystem = new OcclusionSystem();
  });
}


const customMaskShader = `
  precision mediump float;

  varying vec2 vTextureCoord;
  uniform sampler2D uSampler; // Textura do token
  uniform sampler2D uMaskSampler; // Textura da máscara

  void main(void) {
      vec4 originalColor = texture2D(uSampler, vTextureCoord);
      vec4 maskColor = texture2D(uMaskSampler, vTextureCoord);
      
      // Preserva a transparência original do token
      float finalAlpha = originalColor.a * maskColor.a;
      
      gl_FragColor = vec4(1.0, 0.5, 0.2, finalAlpha);
  }
`;

// occlusion.js
export class OcclusionSystem {
  constructor() {
    this.occlusionLayer = null;
    this.tokenContainers = new Map();
    this.maskContainers = new Map();
    this.initialize();
  }

  initialize() {
    // Create a new PIXI container for the occlusion layer
    this.occlusionLayer = new PIXI.Container();
    this.occlusionLayer.name = 'OcclusionLayer';
    this.occlusionLayer.interactive = false;

    // Add the occlusion layer to the canvas stage
    canvas.stage.addChild(this.occlusionLayer);

    Hooks.on('updateToken', (tokenDocument, changes) => {
      if ('x' in changes || 'y' in changes) {
        // Usar setTimeout para garantir que usamos a posição final do token
        requestAnimationFrame(() =>
          this.handleTokenMovement(tokenDocument)
        );
      }
    });

    // Hooks.on('refreshToken', (tokenDocument) => {
    //   this.handleTokenMovement(tokenDocument);
    // });

    // const updateTriggers = [
    //   'canvasReady',
    //   'canvasPan',
    //   'canvasTokensRefresh',
    //   //'updateToken',
    //   'controlToken',
    //   //'refreshToken',
    //   'preUpdateScene',
    //   'updateScene'
    // ];
    // updateTriggers.forEach(hookName => {
    //   Hooks.on(hookName, (tokenDocument) => {
    //     this.handleTokenMovement(tokenDocument);
    //   });
    // });
  }

  handleTokenMovement(tokenDocument) {
    if (!tokenDocument) return;

    const token = tokenDocument.object;
    if (!token) return;

    const tokenId = tokenDocument.id;
    if (!tokenId) return;

    // Clear existing token containers
    this.clearTokenContainers(tokenId);

    // Get tiles that collide with the token
    const collidingTiles = this.getCollidingTiles(token);

    // If there are colliding tiles, create an occlusion mask
    if (collidingTiles.length > 0) {
      this.createOcclusionMask(token, collidingTiles, tokenId);
    }
  }

  getCollidingTiles(token) {
    if (!token || !token.bounds) return [];

    // Filter tiles that overlap with the token's bounds
    return canvas.tiles.placeables.filter(tile => {
      return tile && tile.bounds && token.bounds.overlaps(tile.bounds);
    });
  }
  

  clearTokenContainers(tokenId) {
    if (!tokenId) return;

    // Destroy and remove existing token containers
    if (this.tokenContainers.has(tokenId)) {
      this.tokenContainers.get(tokenId).destroy();
      this.tokenContainers.delete(tokenId);
    }

    if (this.maskContainers.has(tokenId)) {
      this.maskContainers.get(tokenId).destroy();
      this.maskContainers.delete(tokenId);
    }
  }

  createOcclusionMask(token, collidingTiles, tokenId) {
    if (!token || !tokenId) return;

    const tokenMesh = token.mesh;
    if (!tokenMesh) return;

    // Create a custom filter using the custom mask shader
    const customFilter = new PIXI.Filter(null, customMaskShader, {
      uMaskSampler: PIXI.Texture.EMPTY
    });

    // Create non-interactive containers for the token and mask
    const tokenContainer = new PIXI.Container();
    tokenContainer.name = `tokenContainer-${tokenId}`;
    tokenContainer.interactive = false;
    tokenContainer.interactiveChildren = false;

    const maskContainer = new PIXI.Container();
    maskContainer.name = `maskContainer-${tokenId}`;
    maskContainer.interactive = false;
    maskContainer.interactiveChildren = false;

    // Clone the token
    const tokenClone = new PIXI.Sprite(tokenMesh.texture);

    // Set the clone's position, scale, rotation, anchor, and alpha to match the original token
    tokenClone.position.set(token.x, token.y);
    tokenClone.scale.set(tokenMesh.scale.x, tokenMesh.scale.y);
    tokenClone.rotation = tokenMesh.rotation;
    tokenClone.anchor.set(tokenMesh.anchor.x, tokenMesh.anchor.y);
    tokenClone.alpha = tokenMesh.alpha;
    tokenClone.interactive = false;

    tokenContainer.addChild(tokenClone);

    // Create a RenderTexture for the mask
    const maskTexture = PIXI.RenderTexture.create({
      width: canvas.dimensions.width,
      height: canvas.dimensions.height
    });

    // Process colliding tiles and add them to the mask container
    collidingTiles.forEach(tile => {
      const tileMesh = tile.mesh;
      if (!tileMesh) return;

      const tileClone = new PIXI.Sprite(tileMesh.texture);

      // Set the clone's position, scale, rotation, and anchor to match the original tile
      tileClone.position.set(tile.x, tile.y);
      tileClone.scale.set(tileMesh.scale.x, tileMesh.scale.y);
      tileClone.rotation = tileMesh.rotation;
      tileClone.anchor.set(tileMesh.anchor.x, tileMesh.anchor.y);
      tileClone.interactive = false;

      maskContainer.addChild(tileClone);
    });

    // Render the mask container to the mask texture
    canvas.app.renderer.render(maskContainer, {
      renderTexture: maskTexture,
      clear: true
    });

    // Update the mask sampler in the custom filter
    customFilter.uniforms.uMaskSampler = maskTexture;

    // Apply the custom filter to the token container
    tokenContainer.filters = [customFilter];

    // Add the token container to the occlusion layer
    this.occlusionLayer.addChild(tokenContainer);

    // Store references to the token and mask containers
    this.tokenContainers.set(tokenId, tokenContainer);
    this.maskContainers.set(tokenId, maskContainer);

    
  }
}