import Point from "@mapbox/point-geometry";
import LngLat from "../geo/lng_lat.js";
import { v4 as uuid } from "uuid";

const debug = false;
export default class Building {
    constructor(map) {
        this.map = map;
        this.enabled = false; // 是否启用建筑
        this.willRemove = true; // 是否缩放达到一定小后移除建筑图层，以释放资源
        this.lightedBuildings = new Map();
    }

    // 添加building图层
    addbuildings(options) {
        const textures = options.textures;
        this.enabled = true;
        if (textures.length) {
            const textureIDs = new Array(textures.length);
            textures.forEach((texture, index) => {
                const id = `buildingTexture_${uuid()}`;
                this.map.addImage(id, texture);
                textureIDs[index] = id;
            });
            this.map.addLayer(
                {
                    minzoom: 0,
                    maxzoom: 21,
                    id: "3d-buildings",
                    source: "composite",
                    "source-layer": "buildings",
                    type: "fill-extrusion",
                    paint: {
                        "fill-extrusion-building-active-zoom":
                            options.activeZoom,
                        "fill-extrusion-building-remove-zoom":
                            options.removeZoom,
                        "fill-extrusion-lightup": [
                            "case",
                            ["boolean", ["feature-state", "lightup"], false],
                            1,
                            0,
                        ],
                        "fill-extrusion-height": ["get", "height"],
                        "fill-extrusion-map": textureIDs,
                        "fill-extrusion-roofcolor":
                            options.roofcolor === "auto"
                                ? "rgb(255, 255, 254.99)"
                                : options.roofcolor,
                    },
                },
                "primary-label"
            );
        } else {
            this.map.addLayer(
                {
                    minzoom: 0,
                    maxzoom: 21,
                    id: "3d-buildings",
                    source: "composite",
                    "source-layer": "buildings",
                    type: "fill-extrusion",
                    paint: {
                        "fill-extrusion-building-active-zoom":
                            options.activeZoom,
                        "fill-extrusion-building-remove-zoom":
                            options.removeZoom,
                        "fill-extrusion-lightup": [
                            "case",
                            ["boolean", ["feature-state", "lightup"], false],
                            1,
                            0,
                        ],
                        "fill-extrusion-height": ["get", "height"],
                        "fill-extrusion-color": options.buildingColor,
                        "fill-extrusion-opacity": options.opacity,
                    },
                },
                "primary-label"
            );
        }
    }

    // 搜索建筑
    search(options) {
        const result = new Map();
        const center = options.center;
        const samplingRate = options.samplingRate;
        const samplingBearing = options.samplingBearing;
        const coord = new LngLat(center[0], center[1]);

        const originPitch = this.map.getPitch();
        const originZoom = this.map.getZoom();
        const originBearing = this.map.getBearing();
        let bearing = -180;
        this.map.setPitch(0);
        this.map.setZoom(16.1);

        while (bearing <= 180) {
            let point = this.map.project(coord);
            this.searchPerPixel(point, samplingRate, result, "x");
            this.map.setBearing(bearing);
            bearing += samplingBearing;
        }
        if (!debug) {
            this.map.setPitch(originPitch);
            this.map.setZoom(originZoom);
            this.map.setBearing(originBearing);
        }
        return result;
    }

    // 根据每个像素进行搜索建筑
    searchPerPixel(point, samplingRate, result, axis) {
        if (result.get(point.x + "," + point.y)) return;

        let samplePoint = new Point(point.x, point.y);
        let features = this.searchByPoint(samplePoint);
        const originFeatures = features;
        const originPoint = samplePoint;
        while (features.length) {
            const feature = features[features.length - 1];
            const key = samplePoint.x + "," + samplePoint.y;
            result.set(key, feature);
            samplePoint =
                axis === "x"
                    ? new Point(samplePoint.x + samplingRate, samplePoint.y)
                    : new Point(samplePoint.x, samplePoint.y + samplingRate);
            if (axis === "x") {
                this.searchPerPixel(samplePoint, samplingRate, result, "y");
            }
            if (debug) this.addEl(samplePoint);
            features = this.searchByPoint(samplePoint);
        }

        samplePoint = originPoint;
        features = originFeatures;
        while (features.length) {
            const feature = features[features.length - 1];
            const key = samplePoint.x + "," + samplePoint.y;
            result.set(key, feature);
            samplePoint =
                axis === "x"
                    ? new Point(samplePoint.x - samplingRate, samplePoint.y)
                    : new Point(samplePoint.x, samplePoint.y - samplingRate);
            if (axis === "x") {
                this.searchPerPixel(samplePoint, samplingRate, result, "y");
            }
            if (debug) this.addEl(samplePoint);
            features = this.searchByPoint(samplePoint);
        }
    }

    addEl(point) {
        const mapContainer = document.getElementById("map");
        const div = document.createElement("div");
        div.style.position = "absolute";
        div.style.left = point.x + "px";
        div.style.top = point.y + "px";
        div.style.width = "1px";
        div.style.height = "1px";
        div.style.background = "#fff";
        mapContainer.appendChild(div);
    }

    searchByPoint(point) {
        const features = this.map.queryRenderedFeatures(point, {
            layers: ["3d-buildings"],
            usePreciseQuery: true,
        });
        return features;
    }
}
