export function registerOcclusionLayerConfig() {
	// Only enable if the setting is turned on
	//const enableOcclusionLayer = game.settings.get(MODULE_ID, "enableOcclusionLayer");
	//if (!enableOcclusionLayer) return;
 
	// Occlusion layer container
	let occlusionContainer;
	let occlusionTokensLayer;
 
	// Hook into canvas initialization
	Hooks.on('canvasInit', () => {
	  // Remove existing container if it exists
	  if (occlusionContainer) {
		 canvas.stage.removeChild(occlusionContainer);
		 occlusionContainer.destroy({ children: true });
	  }
 
	  // Create the main occlusion container
	  occlusionContainer = new PIXI.Container();
	  occlusionContainer.name = "OcclusionContainer";
	  occlusionContainer.eventMode = 'passive';
 
	  // Create a layer for occlusion tokens
	  occlusionTokensLayer = new PIXI.Container();
	  occlusionTokensLayer.name = "OcclusionTokens";
	  occlusionTokensLayer.sortableChildren = true;
 
	  // Add the layer to the container
	  occlusionContainer.addChild(occlusionTokensLayer);
 
	  // Add to canvas stage
	  canvas.stage.addChild(occlusionContainer);
	  canvas.stage.sortChildren();
	});
 
	// Reset container on scene change
	Hooks.on('changeScene', () => {
	  if (occlusionContainer) {
		 canvas.stage.removeChild(occlusionContainer);
		 occlusionContainer.destroy({ children: true });
		 occlusionContainer = null;
		 occlusionTokensLayer = null;
	  }
	});
 
	// Update occlusion layer when relevant events occur
	const updateTriggers = [
	  'canvasReady', 
	  'canvasTokensRefresh', 
	  'updateToken', 
	  'controlToken', 
	  'refreshToken',
	  'canvasPan'
	];
 
	updateTriggers.forEach(hookName => {
	  Hooks.on(hookName, () => {
		 updateOcclusionLayer();
	  });
	});
 
 
 
 
 
 
	function updateOcclusionLayer() {
	  if (!canvas.ready || !occlusionContainer) return;
 
	  // Clear existing occlusion tokens
	  occlusionTokensLayer.removeChildren();
 
	  // Get all tokens and tiles
	  const tokens = canvas.tokens.placeables;
	  const tiles = canvas.tiles.placeables;
 
	  // Rastreia tokens que já receberam máscara de oclusão
	  const occludedTokens = new Set();
 
	  tokens.forEach(token => {
		 // Find tiles that intersect with this token
		 const intersectingTiles = tiles.filter(tile => 
			checkTokenTileIntersection(token, tile)
		 );
 
		 // If there are intersecting tiles, create an occlusion sprite
		 if (intersectingTiles.length > 0) {
			const occlusionSprite = createOcclusionSprite(token, intersectingTiles);
			if (occlusionSprite) {
			  occlusionTokensLayer.addChild(occlusionSprite);
			}
		 }
	  });
 
	  // Agora, processa oclusão entre tokens
	  for (let i = 0; i < tokens.length; i++) {
		 for (let j = i + 1; j < tokens.length; j++) {
			const tokenA = tokens[i];
			const tokenB = tokens[j];
 
			// Verifica se os tokens estão se sobrepondo
			if (checkTokenTokenIntersection(tokenA, tokenB)) {
			  // Determina qual token deve ser ocluído
			  const [occludedToken, occludingToken] = determineOcclusionPriority(tokenA, tokenB);
 
			  // Cria sprite de oclusão se o token ainda não foi ocluído
			  if (!occludedTokens.has(occludedToken.id)) {
				 const occlusionSprite = createOcclusionSpriteFromTokens(occludedToken, [occludingToken]);
 
				 if (occlusionSprite) {
					occlusionTokensLayer.addChild(occlusionSprite);
					occludedTokens.add(occludedToken.id);
				 }
			  }
			}
		 }
	  }
	}
 
	/*function checkTokenTokenIntersection(tokenA, tokenB) {
	  const boundsA = tokenA.mesh.getBounds();
	  const boundsB = tokenB.mesh.getBounds();
 
	  return (
		 boundsA.x < boundsB.x + boundsB.width &&
		 boundsA.x + boundsA.width > boundsB.x &&
		 boundsA.y < boundsB.y + boundsB.height &&
		 boundsA.y + boundsA.height > boundsB.y
	  );
	}*/
 
	function checkTokenTileIntersection(token, tile) {
	  // Basic intersection check using bounding boxes
	  const tokenBounds = token.mesh.getBounds();
	  const tileBounds = tile.mesh.getBounds();
 
	  return (
		 tokenBounds.x < tileBounds.x + tileBounds.width &&
		 tokenBounds.x + tokenBounds.width > tileBounds.x &&
		 tokenBounds.y < tileBounds.y + tileBounds.height &&
		 tokenBounds.y + tokenBounds.height > tileBounds.y
	  );
	}
 
	function determineOcclusionPriority(tokenA, tokenB) {
	  // Compara o valor de sort dos tokens
	  // O token com maior valor de sort será o que oculta o outro
	  return tokenA.document.sort > tokenB.document.sort 
		 ? [tokenB, tokenA]  // tokenB (menor sort) será ocluído por tokenA
		 : [tokenA, tokenB]; // tokenA (menor sort) será ocluído por tokenB
	}
 
	function createOcclusionSprite(token, intersectingTiles) {
	  if (!token.mesh || !token.mesh.texture) return null;
 
	  try {
		 // Create a sprite from the token's texture
		 const sprite = new PIXI.Sprite(token.mesh.texture);
		 sprite.position.set(token.mesh.position.x, token.mesh.position.y);
		 sprite.anchor.set(token.mesh.anchor.x, token.mesh.anchor.y);
		 sprite.angle = token.mesh.angle;
		 sprite.scale.set(token.mesh.scale.x, token.mesh.scale.y);
 
		 // Create a mask for the occlusion
		 const mask = createOcclusionMask(token, intersectingTiles);
		 if (mask) {
			sprite.mask = mask;
		 }
 
		 // Apply white color filter with 50% opacity
		 /*const colorFilter = new PIXI.filters.ColorReplaceFilter(
			0xffffff,  // white color
			0xffffff,  // white color
			0.5        // threshold
		 );
		 sprite.filters = [colorFilter];*/
 
		 const colorMatrix = new PIXI.ColorMatrixFilter();
		 colorMatrix.matrix = [
			  0, 0, 0, 0, 0,
			  0, 0, 0, 0, 0,
			  1, 1, 1, 0, 0,
			  0, 0, 0, 1, 0
		 ];
		 sprite.filters = [colorMatrix];
 
		 sprite.alpha = 1;
		 sprite.eventMode = 'passive';
 
		 return sprite;
	  } catch (error) {
		 console.error("Error creating occlusion sprite:", error);
		 return null;
	  }
	}
 
	function createOcclusionSpriteFromTokens(occludedToken, occludingTokens) {
	  if (!occludedToken.mesh || !occludedToken.mesh.texture) return null;
 
	  try {
		 // Cria um sprite do token ocluído
		 const sprite = new PIXI.Sprite(occludedToken.mesh.texture);
		 sprite.position.set(
			occludedToken.mesh.position.x, 
			occludedToken.mesh.position.y
		 );
		 sprite.anchor.set(
			occludedToken.mesh.anchor.x, 
			occludedToken.mesh.anchor.y
		 );
		 sprite.angle = occludedToken.mesh.angle;
		 sprite.scale.set(
			occludedToken.mesh.scale.x, 
			occludedToken.mesh.scale.y
		 );
 
		 // Cria máscara de oclusão baseada nos tokens que o estão cobrindo
		 const mask = createTokenOcclusionMask(occludedToken, occludingTokens);
		 if (mask) {
			sprite.mask = mask;
		 }
 
		 // Aplica filtro de cor branca com 50% de opacidade
		 /*const colorFilter = new PIXI.filters.ColorReplaceFilter(
			0xffffff,  // white color
			0xffffff,  // white color
			0.5        // threshold
		 );
		 sprite.filters = [colorFilter];*/
 
		 const colorMatrix = new PIXI.ColorMatrixFilter();
		 colorMatrix.matrix = [
			1.000,  0.000,  0.000,  0.000,  0.000,
			0.000,  0.000,  0.000,  0.000,  0.000, 
			0.000,  0.000,  0.000,  0.000,  0.000, 
			1.000,  0.000,  0.000,  1.000,  0.000
		 ];
		 sprite.filters = [colorMatrix];
 
		 sprite.alpha = 0.5;
		 sprite.eventMode = 'passive';
 
		 return sprite;
	  } catch (error) {
		 console.error("Erro ao criar sprite de oclusão entre tokens:", error);
		 return null;
	  }
	}
 
	function createTokenOcclusionMask(occludedToken, occludingTokens) {
	  const maskGraphics = new PIXI.Graphics();
	  maskGraphics.beginFill(0xffffff);
 
	  occludingTokens.forEach(occludingToken => {
		 const tokenBounds = occludedToken.mesh.getBounds();
		 const occludingBounds = occludingToken.mesh.getBounds();
 
		 const intersectionX = Math.max(tokenBounds.x, occludingBounds.x);
		 const intersectionY = Math.max(tokenBounds.y, occludingBounds.y);
		 const intersectionWidth = Math.min(
			tokenBounds.x + tokenBounds.width, 
			occludingBounds.x + occludingBounds.width
		 ) - intersectionX;
		 const intersectionHeight = Math.min(
			tokenBounds.y + tokenBounds.height, 
			occludingBounds.y + occludingBounds.height
		 ) - intersectionY;
 
		 // Desenha a área de intersecção
		 maskGraphics.drawRect(
			intersectionX, 
			intersectionY, 
			intersectionWidth, 
			intersectionHeight
		 );
	  });
 
	  maskGraphics.endFill();
	  return maskGraphics;
	}
 
	function createOcclusionMask(token, intersectingTiles) {
	  // Create a graphics object to draw the mask
	  const maskGraphics = new PIXI.Graphics();
	  maskGraphics.beginFill(0xffffff);
 
	  intersectingTiles.forEach(tile => {
		 // Calculate intersection area
		 const tokenBounds = token.mesh.getBounds();
		 const tileBounds = tile.mesh.getBounds();
 
		 const intersectionX = Math.max(tokenBounds.x, tileBounds.x);
		 const intersectionY = Math.max(tokenBounds.y, tileBounds.y);
		 const intersectionWidth = Math.min(
			tokenBounds.x + tokenBounds.width, 
			tileBounds.x + tileBounds.width
		 ) - intersectionX;
		 const intersectionHeight = Math.min(
			tokenBounds.y + tokenBounds.height, 
			tileBounds.y + tileBounds.height
		 ) - intersectionY;
 
		 // Draw the intersection area
		 maskGraphics.drawRect(
			intersectionX, 
			intersectionY, 
			intersectionWidth, 
			intersectionHeight
		 );
	  });
 
	  maskGraphics.endFill();
	  return maskGraphics;
	}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
	function checkNonTransparentIntersection(tokenA, tokenB) {
	  // Verifica se as texturas dos tokens existem
	  if (!tokenA.mesh?.texture || !tokenB.mesh?.texture) return false;
 
	  // Obtém os bounds dos tokens
	  const boundsA = tokenA.mesh.getBounds();
	  const boundsB = tokenB.mesh.getBounds();
 
	  // Verifica intersecção básica de bounding box primeiro
	  if (!(
		 boundsA.x < boundsB.x + boundsB.width &&
		 boundsA.x + boundsA.width > boundsB.x &&
		 boundsA.y < boundsB.y + boundsB.height &&
		 boundsA.y + boundsA.height > boundsB.y
	  )) {
		 return false;
	  }
 
	  // Cria um canvas temporário para comparação de pixels
	  const canvas = document.createElement('canvas');
	  const context = canvas.getContext('2d');
 
	  // Define o tamanho do canvas para cobrir a intersecção
	  const intersectionX = Math.max(boundsA.x, boundsB.x);
	  const intersectionY = Math.max(boundsA.y, boundsB.y);
	  const intersectionWidth = Math.min(
		 boundsA.x + boundsA.width, 
		 boundsB.x + boundsB.width
	  ) - intersectionX;
	  const intersectionHeight = Math.min(
		 boundsA.y + boundsA.height, 
		 boundsB.y + boundsB.height
	  ) - intersectionY;
 
	  canvas.width = intersectionWidth;
	  canvas.height = intersectionHeight;
 
	  // Desenha as texturas dos tokens na posição de intersecção
	  function drawTokenTexture(token, offsetX, offsetY) {
		 const texture = token.mesh.texture;
		 const sprite = new PIXI.Sprite(texture);
	  
		 // Converte a textura do PIXI para imagem de canvas
		 const baseTexture = texture.baseTexture;
		 const image = baseTexture.resource.source;
 
		 context.drawImage(
			image, 
			token.mesh.getBounds().x - intersectionX + offsetX, 
			token.mesh.getBounds().y - intersectionY + offsetY,
			token.mesh.width, 
			token.mesh.height
		 );
	  }
 
	  // Desenha ambos os tokens
	  drawTokenTexture(tokenA, 0, 0);
	  drawTokenTexture(tokenB, 0, 0);
 
	  // Verifica pixels na área de intersecção
	  const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
	  const pixels = imageData.data;
 
	  // Conta pixels não transparentes
	  let nonTransparentPixels = 0;
	  for (let i = 3; i < pixels.length; i += 4) {
		 // Se o pixel alfa for maior que um limiar (por exemplo, 10)
		 if (pixels[i] > 50) {
			nonTransparentPixels++;
		 }
	  }
 
	  // Libera recursos
	  canvas.remove();
 
	  // Retorna true se houver pixels não transparentes significativos
	  return nonTransparentPixels > (canvas.width * canvas.height * 0.01); // 1% de pixels não transparentes
	}
 
	// Substitua a função de intersecção existente
	function checkTokenTokenIntersection(tokenA, tokenB) {
	  return checkNonTransparentIntersection(tokenA, tokenB);
	}
 }