"use client";

import Link from "next/link";
import { useEffect, useRef, useState } from "react";
import Map from "@/components/Map";
import BackgroundLayersPanel from "@/components/BackgroundLayersPanel";
import TimelineBar from "@/components/TimelineBar";
import { fetchGeometriesByBBox } from "@/api/geometries";
import { ApiError } from "@/api/http";
import { findEntityTypeOption } from "@/lib/entityTypeOptions";
import {
    BackgroundLayerId,
    BackgroundLayerVisibility,
    DEFAULT_BACKGROUND_LAYER_VISIBILITY,
    HIDDEN_BACKGROUND_LAYER_VISIBILITY,
} from "@/lib/backgroundLayers";
import { Feature, FeatureCollection } from "@/lib/useEditorState";
import {
    loadBackgroundLayerVisibilityFromStorage,
    persistBackgroundLayerVisibility,
} from "@/lib/editor/background/backgroundVisibilityStorage";

const EMPTY_FC: FeatureCollection = { type: "FeatureCollection", features: [] };
const WORLD_BBOX = {
    minLng: -180,
    minLat: -90,
    maxLng: 180,
    maxLat: 90,
} as const;
const CURRENT_YEAR = new Date().getUTCFullYear();
const FALLBACK_TIMELINE_RANGE: TimelineRange = {
    min: -2000,
    max: 2000,
};
const TIMELINE_DEBOUNCE_MS = 180;

type TimelineRange = {
    min: number;
    max: number;
};

export default function Page() {
    const [initialData, setInitialData] = useState<FeatureCollection>(EMPTY_FC);
    const [selectedFeatureId, setSelectedFeatureId] = useState<string | number | null>(null);
    const [timelineYear, setTimelineYear] = useState<number>(() =>
        clampYearValue(CURRENT_YEAR, FALLBACK_TIMELINE_RANGE.min, FALLBACK_TIMELINE_RANGE.max)
    );
    const [timelineDraftYear, setTimelineDraftYear] = useState<number>(() =>
        clampYearValue(CURRENT_YEAR, FALLBACK_TIMELINE_RANGE.min, FALLBACK_TIMELINE_RANGE.max)
    );
    const [isTimelineLoading, setIsTimelineLoading] = useState(false);
    const [timelineStatus, setTimelineStatus] = useState<string | null>(null);
    const [backgroundVisibility, setBackgroundVisibility] = useState<BackgroundLayerVisibility>(
        () => ({ ...HIDDEN_BACKGROUND_LAYER_VISIBILITY })
    );
    const [isBackgroundVisibilityReady, setIsBackgroundVisibilityReady] = useState(false);
    const timelineFetchRequestRef = useRef(0);

    const selectedFeature =
        selectedFeatureId === null
            ? null
            : initialData.features.find((feature) =>
                String(feature.properties.id) === String(selectedFeatureId)
            ) || null;

    useEffect(() => {
        if (selectedFeatureId === null) return;
        const stillExists = initialData.features.some((feature) =>
            String(feature.properties.id) === String(selectedFeatureId)
        );
        if (!stillExists) {
            setSelectedFeatureId(null);
        }
    }, [initialData, selectedFeatureId]);

    useEffect(() => {
        const timeoutId = window.setTimeout(() => {
            if (timelineDraftYear !== timelineYear) {
                setTimelineYear(timelineDraftYear);
            }
        }, TIMELINE_DEBOUNCE_MS);

        return () => window.clearTimeout(timeoutId);
    }, [timelineDraftYear, timelineYear]);

    useEffect(() => {
        setBackgroundVisibility(loadBackgroundLayerVisibilityFromStorage());
        setIsBackgroundVisibilityReady(true);
    }, []);

    useEffect(() => {
        let disposed = false;
        const requestId = ++timelineFetchRequestRef.current;

        async function loadByTimeline() {
            setIsTimelineLoading(true);
            setTimelineStatus(null);

            try {
                const data = await fetchGeometriesByBBox({
                    ...WORLD_BBOX,
                    time: timelineYear,
                });

                if (disposed || requestId !== timelineFetchRequestRef.current) return;
                setInitialData(data);
            } catch (err) {
                if (err instanceof ApiError) {
                    console.error("Load timeline data failed", err.body);
                } else {
                    console.error("Load timeline data failed", err);
                }

                if (!disposed && requestId === timelineFetchRequestRef.current) {
                    setTimelineStatus("Không tải được geometry tại mốc thời gian đã chọn.");
                }
            } finally {
                if (!disposed && requestId === timelineFetchRequestRef.current) {
                    setIsTimelineLoading(false);
                }
            }
        }

        loadByTimeline();

        return () => {
            disposed = true;
        };
    }, [timelineYear]);

    const updateBackgroundVisibility = (
        updater: (prev: BackgroundLayerVisibility) => BackgroundLayerVisibility
    ) => {
        setBackgroundVisibility((prev) => {
            const next = updater(prev);
            persistBackgroundLayerVisibility(next);
            return next;
        });
    };

    const handleToggleBackgroundLayer = (id: BackgroundLayerId) => {
        updateBackgroundVisibility((prev) => ({
            ...prev,
            [id]: !prev[id],
        }));
    };

    const handleShowAllBackgroundLayers = () => {
        updateBackgroundVisibility(() => ({ ...DEFAULT_BACKGROUND_LAYER_VISIBILITY }));
    };

    const handleHideAllBackgroundLayers = () => {
        updateBackgroundVisibility(() => ({ ...HIDDEN_BACKGROUND_LAYER_VISIBILITY }));
    };

    const handleTimelineYearChange = (nextYear: number) => {
        setTimelineDraftYear(clampYear(Math.trunc(nextYear), FALLBACK_TIMELINE_RANGE));
    };

    const selectedType = resolveSelectedTypeSummary(selectedFeature);
    const selectedTimeSummary = formatSelectedTimeSummary(selectedFeature);
    const selectedEntitySummary = formatSelectedEntitySummary(selectedFeature);
    const selectedBindingSummary = formatSelectedBindingSummary(selectedFeature);

    return (
        <div style={{ display: "flex", minHeight: "100vh" }}>
            <div style={{ flex: 1, position: "relative", minHeight: "100vh" }}>
                {isBackgroundVisibilityReady ? (
                    <Map
                        mode="select"
                        draft={initialData}
                        selectedFeatureId={selectedFeatureId}
                        onSelectFeatureId={setSelectedFeatureId}
                        backgroundVisibility={backgroundVisibility}
                        allowGeometryEditing={false}
                        respectBindingFilter={false}
                    />
                ) : (
                    <div style={{ width: "100%", height: "100%", background: "#0b1220" }} />
                )}
                <TimelineBar
                    year={timelineDraftYear}
                    onYearChange={handleTimelineYearChange}
                    isLoading={isTimelineLoading}
                    disabled={false}
                    statusText={timelineStatus}
                />
            </div>

            <BackgroundLayersPanel
                visibility={backgroundVisibility}
                onToggleLayer={handleToggleBackgroundLayer}
                onShowAll={handleShowAllBackgroundLayers}
                onHideAll={handleHideAllBackgroundLayers}
                topContent={
                    <div
                        style={{
                            padding: "10px",
                            background: "#0b1220",
                            borderRadius: "8px",
                            border: "1px solid #1f2937",
                            display: "grid",
                            gap: "8px",
                        }}
                    >
                        <div style={{ fontWeight: 700, fontSize: "14px", color: "#f8fafc" }}>
                            Viewer
                        </div>
                        <div style={{ color: "#94a3b8", fontSize: "12px" }}>
                            Click trực tiếp trên map để chọn geometry.
                        </div>
                        <div style={{ color: "#cbd5e1", fontSize: "13px" }}>
                            {selectedFeature ? `ID: ${String(selectedFeature.properties.id)}` : "Chưa chọn geometry"}
                        </div>
                        <div style={{ color: "#cbd5e1", fontSize: "13px" }}>
                            Type: {selectedType}
                        </div>
                        <div style={{ color: "#cbd5e1", fontSize: "13px" }}>
                            Time: {selectedTimeSummary}
                        </div>
                        <div style={{ color: "#cbd5e1", fontSize: "13px" }}>
                            Entities: {selectedEntitySummary}
                        </div>
                        <div style={{ color: "#cbd5e1", fontSize: "13px" }}>
                            Binding: {selectedBindingSummary}
                        </div>

                        <Link
                            href="/editor"
                            style={{
                                marginTop: "4px",
                                display: "inline-flex",
                                justifyContent: "center",
                                alignItems: "center",
                                borderRadius: "6px",
                                padding: "7px 8px",
                                background: "#1d4ed8",
                                color: "#ffffff",
                                textDecoration: "none",
                                fontSize: "13px",
                                fontWeight: 600,
                            }}
                        >
                            Mở Editor
                        </Link>
                    </div>
                }
            />
        </div>
    );
}

function clampYear(year: number, range: TimelineRange): number {
    return clampYearValue(year, range.min, range.max);
}

function clampYearValue(year: number, minYear: number, maxYear: number): number {
    const lower = Math.min(minYear, maxYear);
    const upper = Math.max(minYear, maxYear);
    if (year < lower) return lower;
    if (year > upper) return upper;
    return year;
}

function isYearNumber(value: number | null | undefined): value is number {
    return typeof value === "number" && Number.isFinite(value);
}

function formatSelectedTimeSummary(feature: Feature | null): string {
    if (!feature) return "Không có";
    const start = isYearNumber(feature.properties.time_start)
        ? String(feature.properties.time_start)
        : "?";
    const end = isYearNumber(feature.properties.time_end)
        ? String(feature.properties.time_end)
        : "?";
    return `${start} → ${end}`;
}

function formatSelectedEntitySummary(feature: Feature | null): string {
    if (!feature) return "Không có";

    const names = Array.isArray(feature.properties.entity_names)
        ? feature.properties.entity_names.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
        : [];
    if (names.length) return names.join(", ");

    if (typeof feature.properties.entity_name === "string" && feature.properties.entity_name.trim().length > 0) {
        return feature.properties.entity_name.trim();
    }

    const ids = Array.isArray(feature.properties.entity_ids)
        ? feature.properties.entity_ids.filter((item): item is string => typeof item === "string" && item.trim().length > 0)
        : [];
    if (ids.length) return ids.join(", ");

    if (typeof feature.properties.entity_id === "string" && feature.properties.entity_id.trim().length > 0) {
        return feature.properties.entity_id.trim();
    }

    return "Chưa gắn";
}

function formatSelectedBindingSummary(feature: Feature | null): string {
    if (!feature) return "Không có";
    const binding = Array.isArray(feature.properties.binding)
        ? feature.properties.binding
            .map((item) => {
                if (typeof item !== "string" && typeof item !== "number") return "";
                return String(item).trim();
            })
            .filter((item) => item.length > 0)
        : [];
    if (!binding.length) return "Không có";
    return binding.join(", ");
}

function resolveSelectedTypeSummary(feature: Feature | null): string {
    if (!feature) return "Không có";
    const typeId = normalizeTypeId(feature.properties.type) || normalizeTypeId(feature.properties.entity_type_id);
    if (!typeId) return "Không có";
    const option = findEntityTypeOption(typeId);
    if (!option) return typeId;
    return `${option.label} (${option.groupLabel})`;
}

function normalizeTypeId(value: unknown): string | null {
    if (typeof value !== "string") return null;
    const normalized = value.trim().toLowerCase();
    return normalized.length ? normalized : null;
}
