import {
  MeshLambertMaterial,
  MeshStandardMaterial,
  MeshPhysicalMaterial,
  MeshPhongMaterial,
  MeshBasicMaterial,
  LineBasicMaterial,
  SpriteMaterial,
  Vector2,
  Object3D,
  Mesh,
  Box3
} from 'three';
import MyCameraControls from '../map/myCameraControls';
import { getObjectsByName } from '../utils';
import { IObjectBaseConfig, IType, OBJECT_NAME } from './index.type';

export const material: Record<string, any> = {
  MeshLambertMaterial,
  MeshStandardMaterial,
  MeshPhysicalMaterial,
  MeshPhongMaterial,
  MeshBasicMaterial,
  LineBasicMaterial,
  SpriteMaterial
};

export const OBJECT_BASE_CONF: Record<IType, IObjectBaseConfig> = {
  floor: {
    name: 'floor',
    material: 'MeshLambertMaterial',
    color: '#fff',
    transparent: true,
    opacity: 1
  },
  park: {
    name: 'park',
    material: 'MeshLambertMaterial',
    color: '#44c3b4',
    transparent: true,
    opacity: 1
    // depthWrite: false,
    // depthTest: false,
  },
  parkBorder: {
    name: 'parkBorder',
    material: 'LineBasicMaterial',
    color: '#f6ffed',
    transparent: true,
    opacity: 1
  },
  pillar: {
    name: 'pillar',
    material: 'MeshLambertMaterial',
    color: '#e7e7e7',
    // depthWrite: false,
    transparent: true,
    opacity: 1
  },
  machine: {
    name: 'machine',
    material: 'SpriteMaterial'
  },
  // 通行设施
  connector: {
    name: 'connector',
    material: 'SpriteMaterial'
  }
};

/**
 * @desc 数组坐标转换为 threejs 坐标
 */
export const arrayPoints23Points = (points: any[]) => {
  const shapePoints: any[] = [];
  let point: Vector2;
  for (let i = 0, len = points.length; i < len; i += 2) {
    point = new Vector2(+points[i], +points[i + 1]);
    shapePoints.push(point);
  }
  return shapePoints;
};

/**
 * @desc 赋值 Material 的时候去掉一些没有必要的属性
 */
export const deletePropertyForMaterial = (conf: any) => {
  const newConf = JSON.parse(JSON.stringify(conf));
  Reflect.deleteProperty(newConf, 'material');
  Reflect.deleteProperty(newConf, 'renderOrder');
  Reflect.deleteProperty(newConf, 'depth');
  return newConf;
};

const renderOrderConf = [
  ['floor'],
  ['park'],
  ['parkBorder'],
  ['pillar'],
  ['machine', 'connector']
];

/**
 * @desc 根据楼层索引返回新的 renderOrder 保证遮盖了比它低的楼层物体
 */
export const getRenderOrderPlusByLevel = (level: number) =>
  renderOrderConf.length * level;

const getRenderOrder = (name: string) => {
  const index = renderOrderConf.findIndex(item =>
    item.find(itemj => itemj === name)
  );
  return index > -1 ? index : 0;
};

/**
 * ！！！需要替换掉
 * @desc 皮肤颜色，初始化时候需要判断本地存储然后把颜色值赋值给 OBJECT_BASE_CONF
 */
export const THEME: Record<'normal', Record<IType, { color: string }>> = {
  normal: {
    floor: { color: '#484f5a' },
    park: { color: '#689f79' },
    parkBorder: { color: '#fff' },
    pillar: { color: '#fff' },
    machine: { color: '' },
    connector: { color: '' }
  }
};

const currTheme = THEME.normal;
for (const key of Object.keys(OBJECT_BASE_CONF)) {
  // @ts-ignore
  OBJECT_BASE_CONF[key].color = currTheme[key].color;
  // @ts-ignore 初始化 渲染顺序 renderOrder
  OBJECT_BASE_CONF[key].renderOrder = getRenderOrder(key);
}

/**
 * @desc 获取当前楼层整体对象
 */
export function getCurrentLevelObj(
  currentLevel: number | string,
  parent: Object3D
) {
  currentLevel = parseInt(currentLevel as string);
  const levelObj = getObjectsByName<Object3D>(OBJECT_NAME.level, parent).find(
    _ => _.userData.zIndex === currentLevel
  );
  return levelObj;
}

export function getDollys(
  targetMesh: Mesh,
  controls: MyCameraControls,
  offset = 5
) {
  if (!targetMesh) {
    return { fitDistance: 0, dollys: [0] };
  }
  const bb = new Box3().setFromObject(targetMesh);
  const fitDistance = controls.getDistanceToFitBox(
    bb.max.x - bb.min.x,
    bb.max.y - bb.min.y,
    bb.max.z - bb.min.z
  );
  const minDollys = [...new Array(offset)]
    .map((_, i) => fitDistance / (i + 2))
    .reverse();
  const maxDollys = [...new Array(offset)].map((_, i) => fitDistance * (i + 2));
  const dollys = [...minDollys, fitDistance, ...maxDollys];
  return { fitDistance, dollys };
}
