import { blankUrn, utopiaUrn } from '@/components/viewer/utils/aps-init';
import { isNotNil } from 'es-toolkit';

function isTemInsideLand(landBounds, temBounds) {
  const tolerance = 0.007;
  return (
    landBounds.min.x - temBounds.min.x <= tolerance
    && landBounds.min.y - temBounds.min.y <= tolerance 
    && landBounds.max.x - temBounds.max.x >= -tolerance 
    && landBounds.max.y - temBounds.max.y >= -tolerance
  );
}

export function findTemInside(land, tems) {
  const temInside = tems.find(tem => {
    const temBounds = tem.bounds[0]; 

    for (const landBounds of land.bounds) {
      if (isTemInsideLand(landBounds, temBounds)) return true; 
    }
  });

  return temInside;
}

export const getTradeCodeFromTem = (tem) => tem.properties.find(prop => prop.displayName === 'LO').displayValue;
export const objIsTem = (obj) => obj.name && obj.name.startsWith('Blk003');
export const objIsLand = (obj) => {
  const layerProp = obj.properties.find((prop) => prop.displayName === 'Layer');
  if (!layerProp) return false;
  const globalWidthProp = obj.properties.find((prop) => prop.displayName === 'Global width');
  return (
    layerProp.displayValue === '1-bodim' ||
    layerProp.displayValue === '0' /* special case - Z.E02.02A */
  ) && globalWidthProp.displayValue === 0;
}

export function findLandByTradeCode(trade_code, lands, temsInside) {
  const foundTemIndex = temsInside.findIndex(tem => tem && getTradeCodeFromTem(tem) === trade_code);
  return foundTemIndex >= 0 ? [lands[foundTemIndex], foundTemIndex] : undefined;
}

export function pan(viewer) {
  const navigation = viewer.navigation;
  const position = navigation.getPosition();
  const target = navigation.getTarget();

  // offset both target and position to maintain angle 
  const panOffset = new THREE.Vector3(2, 0, 0);
  navigation.setPosition(position.clone().add(panOffset));
  navigation.setTarget(target.clone().add(panOffset));
}

export function unloadUnusedExtensions(viewer) {
  viewer.addEventListener(Autodesk.Viewing.EXTENSION_LOADED_EVENT, (e) => {
    if (
      ['Autodesk.Measure', 'Autodesk.DocumentBrowser', 'Autodesk.DefaultTools.NavTools'].includes(e.extensionId)
    ) {
      viewer.unloadExtension(e.extensionId);
    }
  });
}

export function addTemSelectionListener(viewer, products, openProductViewModal, openNoPermissionModal) {
  viewer.addEventListener(Autodesk.Viewing.AGGREGATE_SELECTION_CHANGED_EVENT, (e) => {
    viewer.clearSelection();
    if (e.selections.length !== 1) return;
    const [selectedObj] = e.selections;
    const { model, dbIdArray } = selectedObj;
    if (dbIdArray.length !== 1) return;

    if (model.loader.svfUrn === utopiaUrn) {
      const [dbId] = dbIdArray;
      viewer.getProperties(dbId, (obj) => {
        if (!objIsTem(obj)) return;

        const trade_code = getTradeCodeFromTem(obj);
        const product = products.find(p => p.trade_code === trade_code);
        product ? openProductViewModal(product) : openNoPermissionModal();
      });
    } else if (model.loader.svf.isSceneBuilder) {
      const [dbId] = dbIdArray;
      const product = products.find(p => p.id === dbId);
      product ? openProductViewModal(product) : openNoPermissionModal();
    } else if (model.loader.svfUrn === blankUrn) {
      viewer.clearSelection(); // make unselectable
    }
  },
  (err) => console.error(err),
  );
}

export function getLayerNames() {
  const { viewer } = window;
  if (!viewer) return; 
  if (!viewer.impl) return; 
 
  const layerNames = viewer.impl.layers.indexToLayer
    .filter(obj => isNotNil(obj)) // not counting root
    .filter(obj => obj.visible)
    .map(({ layer }) => layer.name)
    .sort((a, b) => a.localeCompare(b)); 

  return layerNames;
}

export function applyLayerSetting(layersetting, store) {
  const { viewer } = window;
  viewer.setLayerVisible(null, false); // first, hide everything
  viewer.setLayerVisible(layersetting?.detail || null, true); // show specific ones, or all if there's no setting
  store.commit('layersetting', layersetting);
}
