import * as Cesium from 'cesium';

let _clampToGround = false;

const getStyle = (options) => {
  // 将配置项转为cesium内部类，提供复用
  const _options = {}
  // 判断类型（option提供了则套用，未提供测推断）
  if(options.type) {
    _options.type = options.type
  } else if(options.point) {
    _options.type = 'point'
  } else if(options.polygon) {
    _options.type = 'polygon'
  } else if(options.polyline) {
    _options.type = 'polyline'
  } else if(options.billboard) {
    _options.type = 'billboard'
  } else if(options.label) {
    _options.type = 'label'
  } else {
    // 什么配置都没提供，则返回空对象
    return _options
  }

  // 转通用配置
  const common = parseCommonOptions(_options.type, options.common);
  // 属性配置项
  const property = options.property || {};
  property.type = _options.type;

  switch (_options.type) {
    case 'point':
      return parsePointOptions(options, common, property)
    case 'polyline':
      return parsePolylineOptions(options, common, property)
    case 'polygon':
      return parsePolygonOptions(options, common, property)
    case 'billboard':
      return parseBillboardOptions(options, common, property)
    case 'label':
      return parseLabelOptions(options, common, property)
    default:
      console.warn('不支持的样式类型:', _options.type);
      return {}
  }
}

// 解析通用配置
const parseCommonOptions = (type, options) => {
  const _options = {}
  if(!options) {
    return _options
  }
  // 贴地
  if(options.clampToGround) {
    _clampToGround = true;
  }
  // 按视距缩放
  // 线和面没有按视距缩放
  if(options.scaleByDistance && type !== 'polyline' && type !== 'polygon') {
    _options.scaleByDistance = new Cesium.NearFarScalar(
      options.scaleNear,
      options.scaleNearValue,
      options.scaleFar,
      options.scaleFarValue
    );
  }
  return _options
}

/**
 * 解析点相关配置为对象
 * @param {Object} options 总配置项
 * @param {Object} common 通用配置对象
 * @param {Object} property 属性配置对象
 * @returns 点样式对象
 */
const parsePointOptions = (options, common, property) => {
  const style = {
    point: createPointByOptions(options.point, common),
    properties: property || {}
  }
  // 添加图标、标签
  if(options.billboard) {
    style.billboard = createBillboardByOptions(options.billboard, common)
  }
  if(options.label) {
    style.label = createLabelByOptions(options.label, common)
  }
  return style
}

/**
 * 解析点配置项
 * @param {Object} options 点配置项
 * @param {Object} common 通用配置对象
 * @returns cesium点对象
 */
const createPointByOptions = (options, common) => {
  if(!options) {
    return undefined
  }

  const _options = {
    pixelSize: parseFloat(options.pixelSize) || 10,
    color: Cesium.Color.fromCssColorString(options.color) || Cesium.Color.WHITE,
    ...common
  }
  if(options.showOutline) {
    _options.outlineWidth = parseFloat(options.outlineWidth) || 1
    _options.outlineColor = Cesium.Color.fromCssColorString(options.outlineColor) || Cesium.Color.BLACK
  }
  if(_clampToGround) {
    _options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND
  }
  return new Cesium.PointGraphics(_options)
}

/**
 * 解析线相关配置为对象
 * @param {Object} options 总配置项
 * @param {Object} common 通用配置对象
 * @param {Object} property 属性配置对象
 * @returns 线样式对象
 */
const parsePolylineOptions = (options, common, property) => {
  const style = {
    polyline: createPolylineByOptions(options.polyline, common),
    properties: property || {}
  }
  // 添加闭合属性
  if(options.polyline.closed) {
    property.closed = true
  }
  // 添加标签
  if(options.label) {
    style.label = createLabelByOptions(options.label, common)
  }
  return style
}

/**
 * 解析线配置项
 * @param {Object} options 线配置项
 * @param {Object} common 通用配置对象
 * @param {Object} property 属性配置对象
 * @returns cesium线对象
 */
const createPolylineByOptions = (options, common) => {
  if(!options) {
    return undefined
  }

  const _options = {
    width: parseFloat(options.width) || 1,
    material: Cesium.Color.fromCssColorString(options.color) || Cesium.Color.WHITE,
    ...common
  }
  if(_clampToGround) {
    _options.clampToGround = true
  }
  return new Cesium.PolylineGraphics(_options)
}

/**
 * 解析面相关配置为对象
 * @param {Object} options 总配置项
 * @param {Object} common 通用配置对象
 * @param {Object} property 属性配置对象
 * @returns 面样式对象
 */
const parsePolygonOptions = (options, common, property) => {
  const style = {
    polygon: createPolygonByOptions(options.polygon, common),
    properties: property || {}
  }
  // 添加面的轮廓线
  if(options.polygon.showOutline) {
    property.closed = true
    style.polyline = createPolygonOutlineByOptions(options.polygon, common)
  }
  // 添加标签
  if(options.label) {
    style.label = createLabelByOptions(options.label, common)
  }
  return style
}

/**
 * 解析面的轮廓线配置项
 * 因面的自带相关属性不支持贴地形，所以生成cesium线对象
 * @param {Object} options 面配置项
 * @param {Object} common 通用配置对象
 * @returns cesium线对象
 */
const createPolygonOutlineByOptions = (options, common) => {
  if(!options) {
    return undefined
  }

  const _options = {
    width: parseFloat(options.outlineWidth) ?? 1,
    material: Cesium.Color.fromCssColorString(options.outlineColor) || Cesium.Color.BLACK,
    ...common
  }
  if(_clampToGround) {
    _options.clampToGround = true
  }
  return new Cesium.PolylineGraphics(_options)
}

/**
 * 解析面配置项
 * @param {Object} options 面配置项
 * @param {Object} common 通用配置对象
 * @returns cesium面对象
 */
const createPolygonByOptions = (options, common) => {
  if(!options) {
    return undefined
  }

  const _options = {
    material: Cesium.Color.fromCssColorString(options.color) || Cesium.Color.WHITE,
    ...common
  }
  if(_clampToGround) {
    _options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND
  }
  return new Cesium.PolygonGraphics(_options)
}

/**
 * 解析图标相关配置为对象
 * @param {Object} options 总配置项
 * @param {Object} common 通用配置对象
 * @param {Object} property 属性配置对象
 * @returns 图标样式对象
 */
const parseBillboardOptions = (options, common, property) => {
  const style = {
    billboard: createBillboardByOptions(options.billboard, common),
    properties: property || {}
  }
  // 添加标签
  if(options.label) {
    style.label = createLabelByOptions(options.label, common)
  }
  return style
}

/**
 * 解析图标配置项
 * @param {Object} options 图标配置项
 * @param {Object} common 通用配置对象
 * @returns cesium图标对象
 */
const createBillboardByOptions = (options, common) => {
  if(!options) {
    return undefined
  }

  const _options = {
    image: options.image,
    scale: parseFloat(options.scale) ?? 1,
    rotation: Cesium.Math.toRadians(parseFloat(options.rotation) || 0),
    horizontalOrigin: parseInt(options.horizontalOrigin) ?? Cesium.HorizontalOrigin.CENTER,
    verticalOrigin: parseInt(options.verticalOrigin) ?? Cesium.VerticalOrigin.BOTTOM,
    pixelOffset: new Cesium.Cartesian2(parseFloat(options.horizontalOffset) || 0, parseFloat(options.verticalOffset) || 0),
    ...common
  }
  if(_clampToGround) {
    _options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND
  }
  return new Cesium.BillboardGraphics(_options)
}

/**
 * 解析标签相关配置为对象
 * @param {Object} options 总配置项
 * @param {Object} common 通用配置对象
 * @param {Object} property 属性配置对象
 * @returns 标签样式对象
 */
const parseLabelOptions = (options, common, property) => { 
  return {
    label: createLabelByOptions(options.label, common),
    properties: property || {}
  }
}

/**
 * 解析标签配置项
 * @param {Object} options 标签配置项
 * @param {Object} common 通用配置对象
 * @returns cesium标签对象
 */
const createLabelByOptions = (options, common) => {
  if(!options) {
    return undefined
  }

  const _options = {
    font: `${options.font ?? 16}px sans-serif`,
    fillColor: Cesium.Color.fromCssColorString(options.fillColor) || Cesium.Color.WHITE,
    horizontalOrigin: parseInt(options.horizontalOrigin) ?? Cesium.HorizontalOrigin.CENTER,
    verticalOrigin: parseInt(options.verticalOrigin) ?? Cesium.VerticalOrigin.BOTTOM,
    pixelOffset: new Cesium.Cartesian2(parseFloat(options.horizontalOffset) ?? 0, parseFloat(options.verticalOffset) ?? 0),
    ...common
  }
  if(options.showOutline) {
    _options.style = Cesium.LabelStyle.FILL_AND_OUTLINE
    _options.outlineWidth = parseFloat(options.outlineWidth) || 1
    _options.outlineColor = Cesium.Color.fromCssColorString(options.outlineColor) || Cesium.Color.BLACK
  }
  if(options.showBackground) {
    _options.showBackground = true
    _options.backgroundColor = Cesium.Color.fromCssColorString(options.backgroundColor) || new Cesium.Color(0.165, 0.165, 0.165, 0.8)
    _options.backgroundPadding = new Cesium.Cartesian2(parseFloat(options.horizontalPadding) ?? 7, parseFloat(options.verticalPadding) ?? 5)
  }
  if(_clampToGround) {
    _options.heightReference = Cesium.HeightReference.CLAMP_TO_GROUND
  }
  return new Cesium.LabelGraphics(_options)
}
  
export {
  getStyle
}
