<template>
    <div class="bgo-map-locate">
        <div class="bgo-map-locate__map-wrapper">
            <div ref="map" class="bgo-map-locate__map"></div>
            <!-- <van-button
                size="small"
                icon="aim"
                class="bgo-map-locate__locate-btn"
            ></van-button> -->
        </div>
        <div class="bgo-map-locate__search">
            <bgo-search
                v-model="keyword"
                placeholder="搜索"
                @search="onSearch"
            />
        </div>
        <div class="bgo-map-locate__list">
            <van-list
                v-model="loading"
                :finished="finished"
                :error.sync="error"
                @load="onLoad"
            >
                <van-cell
                    v-if="currentLocation"
                    title="[位置]"
                    :label="currentLocation.address"
                    :class="{
                        'is-select': currentLocation.id === selectedLocation.id
                    }"
                    @click="onClickPOI(currentLocation)"
                />
                <van-cell
                    v-for="poi in poiList"
                    :key="poi.id"
                    :title="poi.name"
                    :label="poi.address"
                    :class="{ 'is-select': poi.id === selectedLocation.id }"
                    @click="onClickPOI(poi)"
                />
            </van-list>

            <bgo-empty
                v-if="!loading && poiList.length === 0 && !currentLocation"
                description="范围内没有搜索结果"
            />
        </div>
    </div>
</template>

<script>
/* global AMap*/
import AMapLoader from "@amap/amap-jsapi-loader";
import BgoSearch from "../../Search";
import BgoEmpty from "../../Empty";
import "./index.scss";

export default {
    name: "BgoMapLocate",
    components: { BgoSearch, BgoEmpty },
    props: {
        amapKey: {
            type: String,
            required: true
        },
        enableDrag: {
            type: Boolean,
            default: true
        },
        lngLat: Array,
        radius: {
            type: Number,
            default: 500
        }
    },
    data() {
        return {
            center: this.lngLat ? [...this.lngLat] : [0, 0],

            keyword: "",
            pagination: {
                index: 1,
                size: 20,
                total: 0
            },
            loading: false,
            finished: false,
            error: false,

            poiList: [],
            currentLocation: null,
            selectedLocation: null
        };
    },
    watch: {
        selectedLocation(value) {
            if (value) {
                value = { ...value };
                delete value.id;
            }
            this.$emit("change", value);
        }
    },
    created() {
        this.map = null;
        this.centerMarker = null;
        this.geolocation = null;
        this.placeSearch = null;
        this.geocoder = null;
    },
    mounted() {
        this.initMap();
    },
    methods: {
        /**
         * 初始化地图及插件
         */
        initMap() {
            AMapLoader.load({
                key: this.amapKey,
                plugins: [
                    "AMap.PlaceSearch",
                    "AMap.Geolocation",
                    "AMap.PlaceSearch",
                    "AMap.Geocoder"
                ],
                version: "2.0"
            }).then(AMap => {
                this.map = new AMap.Map(this.$refs.map, {
                    dragEnable: this.enableDrag,
                    resizeEnable: false,
                    zoomEnable: true,
                    rotateEnable: true,
                    pitchEnable: false,
                    zoom: 17,
                    center: this.center
                });
                if (this.enableDrag) {
                    AMap.Event.addListener(
                        this.map,
                        "dragend",
                        this.onMapDragEnd
                    );
                }

                // 实例化地址/逆地址编码服务
                this.geocoder = new AMap.Geocoder();
                AMap.Event.addListener(
                    this.geocoder,
                    "complete",
                    this.onGeocoderComplete
                );

                // 绘制中心点Marker
                this.centerMarker = new AMap.Marker({
                    position: this.lngLat
                        ? new AMap.LngLat(this.lngLat[0], this.lngLat[1])
                        : new AMap.LngLat(0, 0)
                });
                this.map.add(this.centerMarker);

                // 设置地点搜索服务插件
                const placeSearchOptions = {
                    pageSize: this.pagination.size,
                    pageIndex: this.pagination.index,
                    extensions: "base"
                };
                this.placeSearch = new AMap.PlaceSearch(placeSearchOptions);
                // 订阅搜索事件
                AMap.Event.addListener(
                    this.placeSearch,
                    "complete",
                    this.onSearchComplete
                );
                AMap.Event.addListener(
                    this.placeSearch,
                    "fail",
                    this.onSearchFail
                );

                // 设置定位插件
                this.geolocation = new AMap.Geolocation({
                    enableHighAccuracy: true,
                    timeout: 10000,
                    showButton: true,
                    buttonOffset: new AMap.Pixel(10, 20),
                    buttonPosition: "LB",
                    showCircle: false,
                    showMarker: false
                });
                this.map.addControl(this.geolocation);
                // 订阅定位完成事件
                AMap.Event.addListener(
                    this.geolocation,
                    "complete",
                    this.onLocateComplete
                );

                if (!this.lngLat) {
                    // 未传入坐标, 进行定位
                    this.geolocation.getCurrentPosition();
                } else {
                    // 传入坐标, 搜索附近 POI
                    this.onSearch();
                    this.getAddress(this.center[0], this.center[1]);
                }
            });
        },

        /**
         * 设置中心点
         */
        setCenter(lng, lat) {
            if (!this.map || !this.centerMarker) return;

            const lngLat = new AMap.LngLat(lng, lat);
            this.map.setCenter(lngLat);
            this.centerMarker.setPosition(lngLat);
        },

        /**
         * 逆地址解析, 根据坐标获取地址信息
         */
        getAddress(lng, lat) {
            if (!this.geocoder) return;

            this.geocoder.getAddress([lng, lat]);
        },

        /**
         * 搜索中心点附近POI
         */
        searchPOI(keyword = "", page = 1) {
            if (!this.placeSearch) return;

            this.loading = true;
            this.placeSearch.setPageIndex(page);
            this.placeSearch.searchNearBy(keyword, this.center, this.radius);
        },

        /**
         * 搜索框搜索
         */
        onSearch(value) {
            this.pagination.index = 1;
            this.pagination.total = 0;
            this.finished = false;
            this.error = false;
            this.poiList = [];

            this.searchPOI(value);
        },

        /**
         * 列表加载
         */
        onLoad() {
            this.searchPOI(this.keyword, ++this.pagination.index);
        },

        /**
         * 地图拖动结束事件
         */
        onMapDragEnd() {
            const center = this.map.getCenter();
            const lng = center.lng;
            const lat = center.lat;

            this.center = [lng, lat];
            this.setCenter(lng, lat);
            this.getAddress(lng, lat);
            this.onSearch(this.keyword);
        },

        /**
         * 逆地址解析完成回调
         */
        onGeocoderComplete(result) {
            const address = result.regeocode.formattedAddress;
            const location = {
                lng: this.center[0],
                lat: this.center[1]
            };
            this.selectedLocation = this.currentLocation = {
                address,
                location,
                id: "0"
            };
        },

        /**
         * 定位完成回调
         */
        onLocateComplete(result) {
            const position = result.position;
            const lng = position.lng;
            const lat = position.lat;

            this.center = [lng, lat];
            this.setCenter(lng, lat);
            this.getAddress(lng, lat);
            this.onSearch(this.keyword);
        },

        /**
         * POI搜索完成回调
         */
        onSearchComplete(result) {
            this.pagination.total = result.poiList.count;
            this.poiList.push(...result.poiList.pois);

            this.loading = false;
            if (this.poiList.length >= this.pagination.total) {
                this.finished = true;
            }
        },

        /**
         * POI搜索失败
         */
        onSearchFail() {
            this.loading = false;
            this.error = true;
            this.finished = false;
        },

        onClickPOI(poi) {
            const location = poi.location;

            this.setCenter(location.lng, location.lat);

            this.selectedLocation = {
                address: poi.address,
                location: {
                    lng: location.lng,
                    lat: location.lat
                },
                id: poi.id
            };
        }
    }
};
</script>
