import { cloneDeep } from 'lodash';

import { FieldConfigSource, PanelModel, PanelTypeChangedHandler, Threshold, ThresholdsMode } from '@grafana/data';
import { ResourceDimensionMode } from 'app/features/dimensions';

import { MarkersConfig } from './layers/data/markersLayer';
import { getMarkerAsPath } from './style/markers';
import { defaultStyleConfig } from './style/types';
import { GeomapPanelOptions } from './types';
import { MapCenterID } from './view';

/**
 * This is called when the panel changes from another panel
 */
export const mapPanelChangedHandler: PanelTypeChangedHandler = (panel, prevPluginId, prevOptions, prevFieldConfig) => {
  // Changing from angular/worldmap panel to react/openlayers
  if (prevPluginId === 'grafana-worldmap-panel' && prevOptions.angular) {
    const { fieldConfig, options } = worldmapToGeomapOptions({
      ...prevOptions.angular,
      fieldConfig: prevFieldConfig,
    });
    panel.fieldConfig = fieldConfig; // Mutates the incoming panel
    return options;
  }

  return {};
};

export function worldmapToGeomapOptions(angular: any): { fieldConfig: FieldConfigSource; options: GeomapPanelOptions } {
  const fieldConfig: FieldConfigSource = {
    defaults: {},
    overrides: [],
  };

  const options: GeomapPanelOptions = {
    view: {
      id: MapCenterID.Zero,
    },
    controls: {
      showZoom: true,
      mouseWheelZoom: Boolean(angular.mouseWheelZoom),
    },
    basemap: {
      type: 'default', // was carto
      name: 'Basemap',
    },
    layers: [
      // TODO? depends on current configs
    ],
  };

  let v = asNumber(angular.decimals);
  if (v) {
    fieldConfig.defaults.decimals = v;
  }

  // Convert thresholds and color values
  if (angular.thresholds && angular.colors) {
    const levels = angular.thresholds.split(',').map((strVale: string) => {
      return Number(strVale.trim());
    });

    // One more color than threshold
    const thresholds: Threshold[] = [];
    for (const color of angular.colors) {
      const idx = thresholds.length - 1;
      if (idx >= 0) {
        thresholds.push({ value: levels[idx], color });
      } else {
        thresholds.push({ value: -Infinity, color });
      }
    }

    fieldConfig.defaults.thresholds = {
      mode: ThresholdsMode.Absolute,
      steps: thresholds,
    };
  }

  v = asNumber(angular.initialZoom);
  if (v) {
    options.view.zoom = v;
  }

  // mapCenter: 'Europe',
  // mapCenterLatitude: 46,
  // mapCenterLongitude: 14,
  //
  // Map center (from worldmap)
  const mapCenters: any = {
    '(0°, 0°)': MapCenterID.Zero,
    'North America': 'north-america',
    Europe: 'europe',
    'West Asia': 'west-asia',
    'SE Asia': 'se-asia',
    'Last GeoHash': MapCenterID.Coordinates, // MapCenterID.LastPoint,
  };
  options.view.id = mapCenters[angular.mapCenter as any];
  options.view.lat = asNumber(angular.mapCenterLatitude);
  options.view.lon = asNumber(angular.mapCenterLongitude);
  return { fieldConfig, options };
}

function asNumber(v: any): number | undefined {
  const num = +v;
  return isNaN(num) ? undefined : num;
}

export const mapMigrationHandler = (panel: PanelModel): Partial<GeomapPanelOptions> => {
  const pluginVersion = panel?.pluginVersion ?? '';

  // before 8.3, only one layer was supported!
  if (pluginVersion.startsWith('8.1') || pluginVersion.startsWith('8.2')) {
    const layers = panel.options?.layers;
    if (layers?.length === 1) {
      const layer = panel.options.layers[0];
      if (layer?.type === 'markers' && layer.config) {
        // Moving style to child object
        const oldConfig = layer.config;
        const config: MarkersConfig = {
          style: cloneDeep(defaultStyleConfig),
          showLegend: Boolean(oldConfig.showLegend),
        };

        if (oldConfig.size) {
          config.style.size = oldConfig.size;
        }
        if (oldConfig.color) {
          config.style.color = oldConfig.color;
        }
        if (oldConfig.fillOpacity) {
          config.style.opacity = oldConfig.fillOpacity;
        }
        const symbol = getMarkerAsPath(oldConfig.shape);
        if (symbol) {
          config.style.symbol = {
            fixed: symbol,
            mode: ResourceDimensionMode.Fixed,
          };
        }
        return { ...panel.options, layers: [{ ...layer, config }] };
      }
    }
  }
  return panel.options;
};
