# coding=utf-8
import json

from ... import options as opts
from ...charts.chart import Chart
from ...commons import utils
from ...commons.types import List, Numeric, Optional, Sequence, Union
from ...datasets import COORDINATES
from ...globals import ChartType, TooltipFormatterType


class Geo(Chart):
    """
    <<< 地理坐标系 >>>

    地理坐标系组件用于地图的绘制，支持在地理坐标系上绘制散点图，线集。
    """

    def __init__(self, init_opts: Union[opts.InitOpts, dict] = opts.InitOpts()):
        super().__init__(init_opts=init_opts)
        self.set_global_opts()
        self._coordinates = COORDINATES
        self._zlevel = 1

    def add_coordinate(self, name, longitude, latitude):
        self._coordinates.update({name: [longitude, latitude]})

    def add_coordinate_json(self, json_file):
        with open(json_file, "r", encoding="utf-8") as f:
            json_reader = json.load(f)
            for k, v in json_reader.items():
                self.add_coordinate(k, v[0], v[1])

    def get_coordinate(self, name) -> List:
        if name in self._coordinates:
            return self._coordinates[name]

    def add_schema(
        self,
        maptype: str = "china",
        is_roam: bool = True,
        label_opts: Union[opts.LabelOpts, dict, None] = None,
        itemstyle_opts: Union[opts.ItemStyleOpts, dict, None] = None,
        emphasis_itemstyle_opts: Union[opts.ItemStyleOpts, dict, None] = None,
        emphasis_label_opts: Union[opts.LabelOpts, dict, None] = None,
    ):
        if isinstance(label_opts, opts.LabelOpts):
            label_opts = label_opts.opts
        if isinstance(itemstyle_opts, opts.ItemStyleOpts):
            itemstyle_opts = itemstyle_opts.opts
        if isinstance(emphasis_itemstyle_opts, opts.ItemStyleOpts):
            emphasis_itemstyle_opts = emphasis_itemstyle_opts.opts
        if isinstance(emphasis_label_opts, opts.LabelOpts):
            emphasis_label_opts = emphasis_label_opts.opts

        self.js_dependencies.add(maptype)
        self.options.update(
            geo={
                "map": maptype,
                "roam": is_roam,
                "label": label_opts,
                "itemStyle": itemstyle_opts,
                "emphasis": {
                    "itemStyle": emphasis_itemstyle_opts,
                    "label": emphasis_label_opts,
                },
            }
        )
        return self

    def add(
        self,
        series_name: str,
        data_pair: Sequence,
        type_: str = "scatter",
        *,
        is_selected: bool = True,
        symbol: Optional[str] = None,
        symbol_size: Numeric = 12,
        color: Optional[str] = None,
        region_coords: Optional[dict] = None,
        label_opts: Union[opts.LabelOpts, dict] = opts.LabelOpts(),
        effect_opts: Union[opts.EffectOpts, dict] = opts.EffectOpts(),
        linestyle_opts: Union[opts.LineStyleOpts, dict] = opts.LineStyleOpts(),
        tooltip_opts: Union[opts.TooltipOpts, dict, None] = None,
    ):
        if isinstance(label_opts, opts.LabelOpts):
            label_opts = label_opts.opts
        if isinstance(effect_opts, opts.EffectOpts):
            effect_opts = effect_opts.opts
        if isinstance(linestyle_opts, opts.LineStyleOpts):
            linestyle_opts = linestyle_opts.opts
        if isinstance(tooltip_opts, opts.TooltipOpts):
            tooltip_opts = tooltip_opts.opts

        self._zlevel += 1
        if region_coords:
            for city_name, city_coord in region_coords.items():
                self.add_coordinate(city_name, city_coord[0], city_coord[1])

        data = []
        for n, v in data_pair:
            if type_ == ChartType.LINES:
                f, t = self.get_coordinate(n), self.get_coordinate(v)
                data.append({"name": "{}->{}".format(n, v), "coords": [f, t]})
            else:
                lng, lat = self.get_coordinate(n)
                data.append({"name": n, "value": [lng, lat, v]})

        self._append_color(color)
        self._append_legend(series_name, is_selected)

        if type_ == ChartType.SCATTER:
            self.options.get("series").append(
                {
                    "type": type_,
                    "name": series_name,
                    "coordinateSystem": "geo",
                    "symbol": symbol,
                    "symbolSize": symbol_size,
                    "data": data,
                    "label": label_opts,
                    "tooltip": tooltip_opts,
                }
            )

        elif type_ == ChartType.EFFECT_SCATTER:
            self.options.get("series").append(
                {
                    "type": type_,
                    "name": series_name,
                    "coordinateSystem": "geo",
                    "showEffectOn": "render",
                    "rippleEffect": effect_opts,
                    "symbol": symbol,
                    "symbolSize": symbol_size,
                    "data": data,
                    "label": label_opts,
                    "tooltip": tooltip_opts,
                }
            )

        elif type_ == ChartType.HEATMAP:
            self.options.get("series").append(
                {
                    "type": type_,
                    "name": series_name,
                    "coordinateSystem": "geo",
                    "data": data,
                    "tooltip": tooltip_opts,
                }
            )

        elif type_ == ChartType.LINES:
            self.options.get("series").append(
                {
                    "type": type_,
                    "name": series_name,
                    "zlevel": self._zlevel,
                    "effect": effect_opts,
                    "symbol": symbol or ["none", "arrow"],
                    "symbolSize": symbol_size,
                    "data": data,
                    "lineStyle": linestyle_opts,
                    "tooltip": tooltip_opts,
                }
            )

        return self

    def set_global_opts(
        self,
        title_opts: Union[opts.TitleOpts, dict] = opts.TitleOpts(),
        tooltip_opts: Union[opts.TooltipOpts, dict] = opts.TooltipOpts(
            formatter=utils.filter_js_func(TooltipFormatterType.GEO)
        ),
        legend_opts: Union[opts.LegendOpts, dict] = opts.LegendOpts(),
        toolbox_opts: Union[opts.ToolboxOpts, dict] = None,
        xaxis_opts: Union[opts.AxisOpts, dict, None] = None,
        yaxis_opts: Union[opts.AxisOpts, dict, None] = None,
        visualmap_opts: Union[opts.VisualMapOpts, dict, None] = None,
        datazoom_opts: List[Union[opts.DataZoomOpts, dict, None]] = None,
    ):
        return super().set_global_opts(
            title_opts=title_opts,
            tooltip_opts=tooltip_opts,
            legend_opts=legend_opts,
            toolbox_opts=toolbox_opts,
            xaxis_opts=xaxis_opts,
            yaxis_opts=yaxis_opts,
            visualmap_opts=visualmap_opts,
            datazoom_opts=datazoom_opts,
        )
