// // @ts-nocheck
import crossfilter from "crossfilter2";
import * as d3 from "d3";
import mapboxgl from "mapbox-gl";
import 'mapbox-gl/dist/mapbox-gl.css'; // this hides the map for some reason
import { useEffect, useRef } from "react";
import { renderToString } from 'react-dom/server';
import "../assets/Map.css";
import { Metric, type ParameterValues } from "./Parameters";
import { Button } from "./ui/button";
import { ScrollArea } from "./ui/scroll-area";
import { Separator } from "./ui/separator";

export function Map(
    props: {
        listingData: any;
        queryParameters: ParameterValues | null;
    }
) {
    const data = props.listingData;
    var crossData = data.features.map(function (d, i) {
        //clone properties
        var props = clone(d['properties']);
        props['index'] = i;
        return props;
    });
    const cf = crossfilter(crossData);
    const qmDim = cf.dimension(function (d) { return d.qm; });
    const cityDim = cf.dimension(function (d) { return d.city; });
    const countryDim = cf.dimension(function (d) { return d.country; });
    const rentDim = cf.dimension(function (d) { return d.total_price; });
    const roomsDim = cf.dimension(function (d) { return d.rooms; });
    const urlDim = cf.dimension(function (d) { return d.url; });
    const indexDim = cf.dimension(function (d) { return d.index; });
    let heatmap = null;

    // rivet
    var filter = { city: 'London', country: null, mode: Metric.qmprice };
    // filter['countries'] = Array.from(new Set(data.features.map(function (d) { return d['properties']['country'] })));
    if (props.queryParameters) {
        filter['mode'] = props.queryParameters.metric;
    }
    // rivets.bind(document.getElementById('overlay'), { filter: filter });
    const mapRef = useRef(mapboxgl.Map)
    const mapContainerRef = useRef('map-container')
    useEffect(() => {
        mapboxgl.accessToken = 'pk.eyJ1IjoiZGktdG8iLCJhIjoiY2o0bnBoYXcxMW1mNzJ3bDhmc2xiNWttaiJ9.ZccatVk_4shzoAsEUXXecA';
        mapRef.current = new mapboxgl.Map({
            container: mapContainerRef.current,
            style: 'mapbox://styles/mapbox/light-v9',
            center: [13.38032, 49.994210],
            zoom: 5
        });
        mapRef.current.on('load', function () {
            update()
        })
        mapRef.current.on('click', function (e) {
            openListingsDialog(e.lngLat.lng, e.lngLat.lat);
        })
        return () => {
            mapRef.current.remove()
        }
    }, [])


    function clone(d) {
        return JSON.parse(JSON.stringify(d));
    }

    function percentile(arr, p) {
        if (arr.length === 0) return 0;
        if (typeof p !== 'number') throw new TypeError('p must be a number');
        if (p <= 0) return arr[0];
        if (p >= 1) return arr[arr.length - 1];

        var index = arr.length * p,
            lower = Math.floor(index),
            upper = lower + 1,
            weight = index % 1;

        if (upper >= arr.length) return arr[lower];
        return arr[lower] * (1 - weight) + arr[upper] * weight;
    }

    function update() {
        // init heatmap
        heatmap = new HexgridHeatmap(mapRef.current, "hexgrid-heatmap", "waterway-label");
        heatmap.setIntensity(9); // dunno yet
        heatmap.setSpread(0.05); // dunno yet
        heatmap.setCellDensity(0.5); // small value == bigger hexagons
        heatmap.setPropertyName(filter.mode);

        if (filter.mode === Metric.qmprice) {
            // if we visualize sqm based data, remove properties where we have no data
            qmDim.filter(function (d) { return d > 0; });
        }


        // set filter
        if (filter.city) {
            cityDim.filterExact(filter.city);
        } else if (filter.country) {
            countryDim.filterExact(filter.country);
        } else {
            alert('nothing loadable');
        }
        filter.count = cityDim.top(Infinity).length;

        var subset = { "type": "FeatureCollection", "features": [] };
        indexDim.top(Infinity).forEach(function (i) {
            subset.features.push(data.features[i.index]);
        });

        loadData(heatmap, subset);
    }

    function loadData(heatmap, subset) {
        heatmap.setData(subset);
        var values = subset.features.map(function (d) { return d['properties'][filter.mode] });
        values = values.sort(function (a, b) { return a - b; });

        // setting the color stops, min is at 5th percentile, max at 95percentile
        var min = values[Math.round(values.length * 0.05)];
        var max = values[Math.round(values.length * 0.95)];
        var colorStopsPerc = [
            [0, "rgba(0,185,243,0)"],
            [25, "rgba(0,185,243,0.24)"],
            [60, "rgba(255,223,0,0.3)"],
            [100, "rgba(255,105,0,0.3)"],
        ];
        makeLegend(colorStopsPerc, min, max);
        var colorStopsValue = colorStopsPerc.map(function (d) {
            return [min + d[0] * (max - min) / 100, d[1]];
        });
        heatmap.setColorStops(colorStopsValue);
        heatmap.update();

        //get bounding box and zoom to that area
        // we use a 1% percentile since some data can be corrupt
        var longitudes = subset.features.map(function (d) { return d.geometry.coordinates[0]; }).sort(function (a, b) { return a - b; });
        var latitudes = subset.features.map(function (d) { return d.geometry.coordinates[1]; }).sort(function (a, b) { return a - b; });
        var minlng = percentile(longitudes, 0.01);
        var maxlng = percentile(longitudes, 0.99);
        var minlat = percentile(latitudes, 0.01);
        var maxlat = percentile(latitudes, 0.99);
        mapRef.current.fitBounds([
            [minlng, minlat],
            [maxlng, maxlat]
        ]);
    }

    function makeLegend(colorstops, minValue, maxValue) {
        /**
         * colorstops: [[0, 'green'], [100, 'red']]
         * @type {number}
         */
        var svg_height = 300, svg_width = 70;
        var svg = d3.select('#svg');
        var defs = svg
            .attr('height', svg_height)
            .attr('width', svg_width);

        var linearGradient = svg.append("defs")
            .append("linearGradient")
            .attr("id", "linear-gradient");

        linearGradient
            .attr("x1", "0%")
            .attr("y1", "100%")
            .attr("x2", "0%")
            .attr("y2", "0%");

        svg.append("rect")
            .attr("width", svg_width * 0.4)
            .attr("height", svg_height)
            .attr('rx', 4)
            .style("fill", "url(#linear-gradient)");

        colorstops.forEach(function (d) {
            linearGradient.append("stop")
                .attr("offset", d[0] + "%")
                .attr("stop-color", d[1]);
        });


        var xScale = d3.scaleLinear().range([svg_height - 20, 0]).domain([minValue, maxValue]);
        var xAxis = d3.axisRight(xScale).ticks(5);

        svg.append("g")
            .attr("class", "axis")
            .attr("transform", "translate(" + svg_width / 2 + "," + (10) + ")")
            .call(xAxis);
    }

    function openListingsDialog(longtitude, latitude) {
        const searchBuffer = 0.001 // ~100m
        const properties = heatmap._tree.search({
            minX: longtitude - searchBuffer,
            maxX: longtitude + searchBuffer,
            minY: latitude - searchBuffer,
            maxY: latitude + searchBuffer
        })
        if (properties.length > 0) {
            const listingDialogPopup = getListingDialog(properties);
            new mapboxgl.Popup()
                .setLngLat([longtitude, latitude])
                .setHTML(renderToString(listingDialogPopup))
                .setMaxWidth("500px")
                .addTo(mapRef.current);
        }
    }

    function getListingDialog(properties) {
        let listingComponents = [];
        for (let property of properties) {
            listingComponents.push(getPropertyComponent(property));
        }
        console.log(listingComponents.length)
        return <ScrollArea className="rounded-md border">
            <div className="overflow-y-auto h-[500px] w-[500px] scrollbar-thin scrollbar-thumb-rounded">

                <div className="propertyListingPopupItem" style={{ width: '100%' }}>
                    Showing <strong>{properties.length}</strong> properties
                </div>
                {listingComponents.map((item) => {
                    const scrollDiv = <div key={item.key}>
                        {item}
                        <Separator className="my-2" />
                    </div>;
                    return scrollDiv
                })}
            </div>
        </ScrollArea>;
    }

    function getPropertyComponent(property) {
        const priceHistoryHTMLs = property.properties.price_history.map((d) => {
            return <li key={d.id}>${d.last_seen.split('T')[0]}: £${d.price}</li>;
        });

        let priceHistoryHTML = <></>;
        if (priceHistoryHTMLs.length > 1) {
            priceHistoryHTML =
                <div className="propertyListingPopupItem">
                    <strong>Price history:</strong>
                    <ul>
                        ${priceHistoryHTMLs.join('')}
                    </ul>
                    <br />
                </div>

        }
        const lastSeenStr = property.properties.last_seen.split('T')[0];
        const lastSeenDays = Math.round((new Date() - new Date(lastSeenStr)) / (1000 * 60 * 60 * 24));
        return <div key={property.properties.url} style={{ display: 'flex', flexWrap: 'wrap' }}>
            <div className="propertyListingPopupItem" style={{ width: '100%' }}>
                <img src={property.properties.photo_thumbnail} />
            </div>
            <div className="propertyListingPopupItem">
                <strong>Available from:</strong>
            </div>
            <div className="propertyListingPopupItem">
                {property.properties.available_from}
            </div>
            <div className="propertyListingPopupItem">
                <strong>Price:</strong>
            </div>
            <div className="propertyListingPopupItem">
                £{property.properties.total_price}
            </div>
            {priceHistoryHTML}
            <div className="propertyListingPopupItem">
                <strong>Rooms:</strong>
            </div>
            <div className="propertyListingPopupItem">

                {property.properties.rooms}
            </div>
            <div className="propertyListingPopupItem">
                <strong>Area:</strong>
            </div>
            <div className="propertyListingPopupItem">
                {property.properties.qm} m²
            </div>
            <div className="propertyListingPopupItem">
                <strong>Price per area:</strong>
            </div>
            <div className="propertyListingPopupItem">
                £{property.properties.qmprice}/m²
            </div>
            <div className="propertyListingPopupItem">
                <strong>Last seen:</strong>
            </div>
            <div className="propertyListingPopupItem">
                {lastSeenDays} days ago
            </div>
            <div className="propertyListingPopupItem">
                <strong>Agency:</strong>
            </div>
            <div className="propertyListingPopupItem">
                {property.properties.agency}
            </div>
            <div className="propertyListingPopupItem" style={{ width: '100%' }}>
                <Button asChild>
                    <a href={property.properties.url} target="_blank">View Listing</a>
                </Button>
            </div>
        </div>
    }

    return <>
        <div id='map-container' ref={mapContainerRef}></div>

        <div id="legend">
            <svg id="svg">
            </svg>
        </div>
    </>
}
