import { scene, newMetaDataEntry, selectedMeshes, updateCamera, updateEnvironment, buildMaterialsArray, buildSelectedMaterialArray, serializeScene } from '../helpers';
import { reactProps as props } from '../Canvas';
import { deleteSelected } from '../actions';
import { TRANSPARENCY_MODES } from '../constants';
import * as BABYLON from 'babylonjs';
import _ from 'lodash';
const removeChannelFromTexture = (image, channel) => {
  const imageHeight = image?.naturalHeight ?? 0;
  const imageWidth = image?.naturalWidth ?? 0;
  let imageData;
  const maxHeight = Math.max(...[imageHeight, 1024]);
  const maxWidth = Math.max(...[imageWidth, 1024]);
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  canvas.width = maxWidth;
  canvas.height = maxHeight;
  if (image) {
    ctx.drawImage(image, 0, 0, maxWidth, maxHeight);
    imageData = ctx.getImageData(0, 0, maxWidth, maxHeight).data;
  }
  const combinedImageData = ctx.createImageData(maxWidth, maxHeight);
  const combinedData = combinedImageData.data;
  for (let i = 0; i < combinedData.length; i += 4) {
    combinedData[i] = channel === 'R' ? 0 : imageData[i];
    combinedData[i + 1] = channel === 'G' ? 0 : imageData[i + 1];
    combinedData[i + 2] = channel === 'B' ? 0 : imageData[i + 2];
    combinedData[i + 3] = channel === 'A' ? 255 : imageData[i + 3];
  }
  ctx.putImageData(combinedImageData, 0, 0);
  return canvas.toDataURL('image/png');
};
const textureToImage = texture => {
  return new Promise(resolve => {
    if (!texture.readPixels()) {
      resolve(null);
      return;
    }
    texture.readPixels().then(pixels => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      const {
        width,
        height
      } = texture.getSize();
      canvas.width = width;
      canvas.height = height;
      const img = new Image();
      const imageData = ctx.createImageData(width, height);
      imageData.data.set(new Uint8ClampedArray(pixels));
      ctx.putImageData(imageData, 0, 0);
      img.onload = () => {
        resolve(img);
      };
      img.onerror = () => {
        resolve(null);
      };
      img.src = canvas.toDataURL();
    }).catch(() => {
      resolve(null);
    });
  });
};
export const removeFromMaterial = inboundData => {
  const {
    payload
  } = inboundData;
  const {
    id,
    removeAlbedoTexture,
    removeMetallicTexture,
    removeMicroSurfaceTexture,
    removeEmissiveTexture,
    removeBumpTexture,
    removeOpacityTexture,
    removeRoughnessTexture,
    removeAmbientTexture
  } = payload;
  const material = scene.getMaterialByName(id, true);
  if (material) {
    // Basic attribute textures.
    if (removeAlbedoTexture) {
      const isStencil = material.transparencyType === TRANSPARENCY_MODES.stencil;
      if (isStencil) {
        material.albedoTexture.hasAlpha = false;
        material.albedoTexture.useAlphaFromAlbedoTexture = false;
        material.transparencyMode = BABYLON.PBRMaterial.PBRMATERIAL_ALPHABLEND;
        material.transparencyType = TRANSPARENCY_MODES.simple;
      }
      material.albedoTexture?.dispose();
      material.albedoTexture = null;
    }
    if (removeMetallicTexture) {
      if (material.metallicTexture) {
        textureToImage(material.metallicTexture).then(data => {
          const updatedTexture = removeChannelFromTexture(data, 'B');
          material.metallicTexture.updateURL(updatedTexture);
          newMetaDataEntry('materials', buildMaterialsArray());
          newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
          props.clearNotifications?.();
          props.setSerializedData?.(serializeScene());
        }).catch(() => {
          console.log('Failed to remove metallic texture');
        });
      }
    }
    if (removeMicroSurfaceTexture) {
      material.microSurfaceTexture?.dispose();
      material.microSurfaceTexture = null;
    }
    if (removeEmissiveTexture) {
      material.emissiveTexture?.dispose();
      material.emissiveTexture = null;
    }
    if (removeBumpTexture) {
      material.bumpTexture?.dispose();
      material.bumpTexture = null;
    }
    if (removeOpacityTexture) {
      material.opacityTexture?.dispose();
      material.opacityTexture = null;
    }
    if (removeAmbientTexture) {
      material.ambientTexture?.dispose();
      material.ambientTexture = null;
    }
    if (removeRoughnessTexture) {
      if (material.metallicTexture) {
        textureToImage(material.metallicTexture).then(data => {
          const updatedTexture = removeChannelFromTexture(data, 'G');
          material.metallicTexture.updateURL(updatedTexture);
          newMetaDataEntry('materials', buildMaterialsArray());
          newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
          props.clearNotifications?.();
          props.setSerializedData?.(serializeScene());
        }).catch(() => {
          console.log('Failed to remove roughness texture');
        });
      }
    }
    newMetaDataEntry('materials', buildMaterialsArray());
    newMetaDataEntry('selectedMaterials', buildSelectedMaterialArray());
  }
};
export const removeFromMesh = inboundData => {
  const {
    payload
  } = inboundData;
  const {
    id
  } = payload;
  if (_.isString(id)) {
    if (_.isEmpty(selectedMeshes) || selectedMeshes.length > 1) {
      return;
    }
    const selectedMesh = selectedMeshes[0];

    // Remove custom user mesh positions.
    const userMeshPositions = scene.metadata?.userMeshPositions?.filter(mesh => mesh.meshId !== selectedMesh.id || mesh.positionId !== id) || [];
    const filteredSelectedPositions = scene.metadata.selectedUserMeshPositions.filter(pos => pos.meshId !== selectedMesh.id || pos.positionId !== id);
    const defaultPosition = userMeshPositions.find(pos => pos.meshId === selectedMesh.id && pos.positionId === 'Default');
    filteredSelectedPositions.push(defaultPosition);
    newMetaDataEntry('userMeshPositions', userMeshPositions);
    newMetaDataEntry('selectedUserMeshPositions', filteredSelectedPositions);
  }
};
export const removeFromCamera = inboundData => {
  const {
    payload
  } = inboundData;
  const {
    id
  } = payload;
  if (_.isString(id)) {
    // Custom user camera views.
    const filteredPositions = scene.metadata?.userCameraViews.filter(cameraPos => cameraPos.id !== id) || [];
    const inboundData = {
      payload: {
        resetCamera: true
      }
    };
    newMetaDataEntry('userCameraViews', filteredPositions);
    updateCamera(inboundData);
  }
};
export const removeFromEnvironment = inboundData => {
  const {
    payload
  } = inboundData;
  const {
    id
  } = payload;
  const userEnv = scene.metadata?.userEnvironments.find(env => env.id === id);

  // remove custom user environment.
  if (_.isString(id) && _.isString(userEnv?.url)) {
    const filteredEnvs = scene.metadata?.userEnvironments.filter(env => env.id != id) || [];
    const inboundData = {
      payload: {
        url: scene.metadata.defaultEnvironment,
        transforms: {
          rotation: {
            ry: scene.metadata.environmentRotation
          }
        }
      }
    };
    newMetaDataEntry('userEnvironments', filteredEnvs);
    updateEnvironment(inboundData);
  }
};
export const removeFromViewport = inboundData => {
  const {
    payload
  } = inboundData;
  const {
    deleteSelectedMesh
  } = payload;
  const hasSelection = selectedMeshes.length > 0;

  // Delete selected mesh.
  if (deleteSelectedMesh !== undefined && hasSelection) {
    const multiSelection = selectedMeshes.length > 1;
    const confirmConfig = {
      message: `Are you sure you want to delete ${multiSelection ? 'these meshes' : 'this mesh'}?`,
      onConfirm: () => deleteSelected(),
      onClose: () => props.setConfirmMessage?.(null)
    };
    props.setConfirmMessage?.(confirmConfig);
  }
};