// Enhanced Occlusion Layer Module for Foundry VTT

export function registerOcclusionConfig() {
  Hooks.once('ready', () => {
    TokenOcclusionManager.initialize();
  });
}

// Shader personalizado para detectar sobreposição de pixels
const occlusionShader = `
  precision mediump float;

  varying vec2 vTextureCoord;
  uniform sampler2D uSampler;
  uniform sampler2D tileTexture;
  uniform vec4 uColorMatrix;      // Color in RGBA normalized floats
  uniform vec4 tileArea;          // x, y, width, height em coordenadas UV

  void main(void) {
    vec4 tokenColor = texture2D(uSampler, vTextureCoord);
    vec4 tokenMixColor = tokenColor * uColorMatrix;
    
    // Amostra o pixel do tile na mesma posição
    vec4 tileColor = texture2D(tileTexture, vTextureCoord);
          
    // Se o tile tiver alpha > 0, aplica o efeito de oclusão
    if (tokenColor.a > 0.1) {
      gl_FragColor = tokenMixColor; // Cor azul mantendo o alpha original
    } else {
      discard;
    }
  }
`;




class TokenOcclusionFilter extends PIXI.Filter {
	constructor(tile) {
		super(null, occlusionShader);
		this.tile = tile;
		this.uniforms.tileTexture = tile.texture;
    this.uniforms.uColorMatrix = new Float32Array([0.2, 0.3, 0.9, 1.0]);
    this.uniforms.uOutlineColor = new Float32Array([0.2, 0.3, 0.9, 1.0]);
    this.uniforms.uOutlineThickness = 2.0; // Largura do outline em pixels
		this.updateTileArea();
	}

  updateTileArea() {
    // Obtém os bounds da textura do tile
    const tileBounds = this.tile.mesh.getBounds();
    const tileTexture = this.tile.texture;
    
    // Calcula as coordenadas UV baseadas nos bounds da textura
    const textureFrame = tileTexture.frame;
    const textureWidth = textureFrame.width;
    const textureHeight = textureFrame.height;
    
    this.uniforms.tileArea = new Float32Array([
        tileBounds.x / textureWidth,
        tileBounds.y / textureHeight,
        tileBounds.width / textureWidth,
        tileBounds.height / textureHeight
    ]);
  }
}









// Função principal para gerenciar a oclusão
class TokenOcclusionManager {
	static initialize() {
		// Registra o hook para atualizar a oclusão quando tokens são atualizados
		Hooks.on("refreshToken", (token) => {
			this.updateTokenOcclusion(token);
		});
	}

	static updateTokenOcclusion(token) {
		// Remove filtros antigos de oclusão
		token.mesh.filters = token.mesh.filters?.filter(f => !(f instanceof TokenOcclusionFilter)) || [];
        
		// Obtém todos os tiles da cena atual
		const tiles = canvas.tiles.placeables;
        
		// Verifica sobreposição com cada tile
		for (const tile of tiles) {
			if (this.checkTextureOverlap(token, tile)) {
				const occlusionFilter = new TokenOcclusionFilter(tile);
				token.mesh.filters.push(occlusionFilter);
			}
		}
	}

  static checkTextureOverlap(token, tile) {
    // Obtém os bounds das texturas
    const tokenTextureBounds = token.mesh.getBounds();
    const tileTextureBounds = tile.mesh.getBounds();
      
    // Verifica sobreposição usando os bounds das texturas
    const hasOverlap = !(
        tokenTextureBounds.right < tileTextureBounds.left ||
        tokenTextureBounds.left > tileTextureBounds.right ||
        tokenTextureBounds.bottom < tileTextureBounds.top ||
        tokenTextureBounds.top > tileTextureBounds.bottom
    );

    // Verifica se ambas as texturas têm conteúdo visível
    const tokenHasContent = token.texture && token.texture.valid;
    const tileHasContent = tile.texture && tile.texture.valid;

    return hasOverlap && tokenHasContent && tileHasContent;
  }
}