"use client";

import { useEffect, useMemo, useRef, useState, type CSSProperties } from "react";
import { searchGeometriesByEntityName, type EntityGeometriesSearchItem, type EntityGeometrySearchGeo } from "@/uhm/api/geometries";
import {
    fetchPresentPlaceDetail,
    hasSearchMapApiKey,
    reverseGeocodePresentPlace,
    searchPresentPlaces,
    type PresentPlacePrediction,
    type PresentPlaceSelection,
} from "@/uhm/api/goongPlaces";
import { getGeometryRepresentativePoint } from "@/uhm/components/map/mapUtils";
import { searchWikisByTitle, type Wiki } from "@/uhm/api/wikis";

export type { PresentPlaceSelection } from "@/uhm/api/goongPlaces";

export type HistoricalGeometryFocusPayload = {
    entity: EntityGeometriesSearchItem;
    geometry: EntityGeometrySearchGeo;
    representativePoint: [number, number] | null;
    adminLabel: string | null;
};

type SearchMode = "present" | "history" | "wiki";

type AdminLabelState = {
    status: "loading" | "loaded" | "error";
    label: string | null;
    address: string | null;
};

type Props = {
    focusedPlace: PresentPlaceSelection | null;
    onFocusPlace: (place: PresentPlaceSelection) => void;
    onFocusHistoricalGeometry: (payload: HistoricalGeometryFocusPayload) => void;
    onFocusWiki?: (wiki: Wiki) => void;
    onClearFocus: () => void;
    leftOffset?: number;
    style?: CSSProperties;
};

export default function PresentPlaceSearch({
    focusedPlace,
    onFocusPlace,
    onFocusHistoricalGeometry,
    onFocusWiki,
    onClearFocus,
    leftOffset = 18,
    style,
}: Props) {
    const [mode, setMode] = useState<SearchMode>("history");
    const [query, setQuery] = useState("");
    const [results, setResults] = useState<PresentPlacePrediction[]>([]);
    const [isLoading, setIsLoading] = useState(false);
    const [selectingPlaceId, setSelectingPlaceId] = useState<string | null>(null);
    const [error, setError] = useState<string | null>(null);

    const [historicalQuery, setHistoricalQuery] = useState("");
    const [historicalResults, setHistoricalResults] = useState<EntityGeometriesSearchItem[]>([]);
    const [isHistoricalLoading, setIsHistoricalLoading] = useState(false);
    const [historicalError, setHistoricalError] = useState<string | null>(null);
    const [expandedEntityId, setExpandedEntityId] = useState<string | null>(null);
    const [selectingGeometryId, setSelectingGeometryId] = useState<string | null>(null);
    const [adminLabels, setAdminLabels] = useState<Record<string, AdminLabelState>>({});

    const [wikiQuery, setWikiQuery] = useState("");
    const [wikiResults, setWikiResults] = useState<Wiki[]>([]);
    const [isWikiLoading, setIsWikiLoading] = useState(false);
    const [wikiError, setWikiError] = useState<string | null>(null);

    const [isOpen, setIsOpen] = useState(false);
    const requestSeqRef = useRef(0);
    const historicalRequestSeqRef = useRef(0);
    const wikiRequestSeqRef = useRef(0);
    const hasApiKey = hasSearchMapApiKey();

    const activeQuery = mode === "present" ? query : mode === "history" ? historicalQuery : wikiQuery;
    const activeError = mode === "present" ? error : mode === "history" ? historicalError : wikiError;
    const activeLoading = mode === "present" ? isLoading : mode === "history" ? isHistoricalLoading : isWikiLoading;

    const expandedItem = useMemo(() => {
        if (!expandedEntityId) return null;
        return historicalResults.find((item) => item.entity_id === expandedEntityId) || null;
    }, [expandedEntityId, historicalResults]);

    useEffect(() => {
        if (mode !== "present") return;

        const keyword = query.trim();
        if (!keyword || keyword.length < 2) {
            setResults([]);
            setIsLoading(false);
            setError(null);
            return;
        }

        if (!hasApiKey) {
            setResults([]);
            setIsLoading(false);
            setError("Thiếu SEARCH_MAP_API_KEY.");
            return;
        }

        const controller = new AbortController();
        const seq = requestSeqRef.current + 1;
        requestSeqRef.current = seq;
        const timer = window.setTimeout(() => {
            setIsLoading(true);
            setError(null);
            searchPresentPlaces(keyword, controller.signal)
                .then((nextResults) => {
                    if (requestSeqRef.current !== seq) return;
                    setResults(nextResults);
                    setIsOpen(true);
                })
                .catch((err) => {
                    if (controller.signal.aborted || requestSeqRef.current !== seq) return;
                    setResults([]);
                    setError(err instanceof Error ? err.message : "Không tìm được địa điểm.");
                })
                .finally(() => {
                    if (requestSeqRef.current === seq) {
                        setIsLoading(false);
                    }
                });
        }, 260);

        return () => {
            window.clearTimeout(timer);
            controller.abort();
        };
    }, [hasApiKey, mode, query]);

    useEffect(() => {
        if (mode !== "history") return;

        const keyword = historicalQuery.trim();
        if (!keyword || keyword.length < 2) {
            setHistoricalResults([]);
            setIsHistoricalLoading(false);
            setHistoricalError(null);
            setExpandedEntityId(null);
            return;
        }

        const seq = historicalRequestSeqRef.current + 1;
        historicalRequestSeqRef.current = seq;
        const timer = window.setTimeout(() => {
            setIsHistoricalLoading(true);
            setHistoricalError(null);
            searchGeometriesByEntityName(keyword, { limit: 12 })
                .then((response) => {
                    if (historicalRequestSeqRef.current !== seq) return;
                    setHistoricalResults(response.items || []);
                    setExpandedEntityId(null);
                    setIsOpen(true);
                })
                .catch((err) => {
                    if (historicalRequestSeqRef.current !== seq) return;
                    setHistoricalResults([]);
                    setHistoricalError(err instanceof Error ? err.message : "Không tìm được thực thể lịch sử.");
                })
                .finally(() => {
                    if (historicalRequestSeqRef.current === seq) {
                        setIsHistoricalLoading(false);
                    }
                });
        }, 260);

        return () => window.clearTimeout(timer);
    }, [historicalQuery, mode]);

    useEffect(() => {
        if (mode !== "wiki") return;

        const keyword = wikiQuery.trim();
        if (!keyword || keyword.length < 2) {
            setWikiResults([]);
            setIsWikiLoading(false);
            setWikiError(null);
            return;
        }

        const seq = wikiRequestSeqRef.current + 1;
        wikiRequestSeqRef.current = seq;
        const timer = window.setTimeout(() => {
            setIsWikiLoading(true);
            setWikiError(null);
            searchWikisByTitle(keyword, { limit: 12 })
                .then((nextResults) => {
                    if (wikiRequestSeqRef.current !== seq) return;
                    setWikiResults(nextResults || []);
                    setIsOpen(true);
                })
                .catch((err) => {
                    if (wikiRequestSeqRef.current !== seq) return;
                    setWikiResults([]);
                    setWikiError(err instanceof Error ? err.message : "Không tìm được bài viết wiki.");
                })
                .finally(() => {
                    if (wikiRequestSeqRef.current === seq) {
                        setIsWikiLoading(false);
                    }
                });
        }, 260);

        return () => window.clearTimeout(timer);
    }, [wikiQuery, mode]);

    useEffect(() => {
        if (mode !== "history" || !expandedItem || expandedItem.geometries.length <= 1 || !hasApiKey) {
            return;
        }

        const controller = new AbortController();
        for (const geometry of expandedItem.geometries) {
            const point = getGeometryRepresentativePoint(geometry.draw_geometry);
            if (!point) {
                setAdminLabels((prev) => ({
                    ...prev,
                    [geometry.id]: { status: "error", label: null, address: null },
                }));
                continue;
            }

            setAdminLabels((prev) => {
                if (prev[geometry.id]) return prev;
                return {
                    ...prev,
                    [geometry.id]: { status: "loading", label: null, address: null },
                };
            });

            reverseGeocodePresentPlace(point[0], point[1], controller.signal)
                .then((place) => {
                    setAdminLabels((prev) => ({
                        ...prev,
                        [geometry.id]: {
                            status: "loaded",
                            label: place.label,
                            address: place.address,
                        },
                    }));
                })
                .catch((err) => {
                    if (controller.signal.aborted) return;
                    console.warn("Reverse geocode historical geometry failed", err);
                    setAdminLabels((prev) => ({
                        ...prev,
                        [geometry.id]: { status: "error", label: null, address: null },
                    }));
                });
        }

        return () => controller.abort();
    }, [expandedItem, hasApiKey, mode]);

    const selectPrediction = async (prediction: PresentPlacePrediction) => {
        setSelectingPlaceId(prediction.placeId);
        setError(null);
        try {
            const place = await fetchPresentPlaceDetail(prediction.placeId);
            onFocusPlace(place);
            setQuery(place.name || prediction.description);
            setResults([]);
            setIsOpen(false);
        } catch (err) {
            setError(err instanceof Error ? err.message : "Không lấy được tọa độ địa điểm.");
        } finally {
            setSelectingPlaceId(null);
        }
    };

    const selectHistoricalEntity = (item: EntityGeometriesSearchItem) => {
        if (item.geometries.length === 1) {
            selectHistoricalGeometry(item, item.geometries[0]);
            return;
        }
        if (item.geometries.length > 1) {
            setExpandedEntityId((prev) => prev === item.entity_id ? null : item.entity_id);
        }
    };

    const selectHistoricalGeometry = (
        item: EntityGeometriesSearchItem,
        geometry: EntityGeometrySearchGeo
    ) => {
        setSelectingGeometryId(geometry.id);
        const labelState = adminLabels[geometry.id] || null;
        onFocusHistoricalGeometry({
            entity: item,
            geometry,
            representativePoint: getGeometryRepresentativePoint(geometry.draw_geometry),
            adminLabel: labelState?.label || null,
        });
        setHistoricalQuery(item.name);
        setHistoricalResults([]);
        setExpandedEntityId(null);
        setIsOpen(false);
        setSelectingGeometryId(null);
    };

    const selectWiki = (wiki: Wiki) => {
        if (onFocusWiki) {
            onFocusWiki(wiki);
        }
        setWikiQuery(wiki.title || "");
        setWikiResults([]);
        setIsOpen(false);
    };

    const clearSearch = () => {
        if (mode === "present") {
            setQuery("");
            setResults([]);
            setError(null);
        } else if (mode === "history") {
            setHistoricalQuery("");
            setHistoricalResults([]);
            setHistoricalError(null);
            setExpandedEntityId(null);
        } else {
            setWikiQuery("");
            setWikiResults([]);
            setWikiError(null);
        }
        setIsOpen(false);
        onClearFocus();
    };

    const cycleMode = () => {
        let nextMode: SearchMode;
        if (mode === "history") {
            nextMode = "present";
        } else if (mode === "present") {
            nextMode = "wiki";
        } else {
            nextMode = "history";
        }
        setMode(nextMode);
        setIsOpen(true);
        setError(null);
        setHistoricalError(null);
        setWikiError(null);
    };

    return (
        <div
            style={{
                position: "absolute",
                top: 10,
                left: "50%",
                transform: "translateX(-50%)",
                zIndex: 18,
                width: "min(392px, calc(100vw - 36px))",
                pointerEvents: "auto",
                ...style,
            }}
            onMouseDown={(event) => event.stopPropagation()}
        >
            <div style={searchCardStyle}>
                <div style={searchInputRowStyle}>
                    <button
                        type="button"
                        onClick={cycleMode}
                        title={`Đổi chế độ tìm kiếm (hiện tại: ${getSearchModeLabel(mode)})`}
                        aria-label={`Đổi chế độ tìm kiếm (hiện tại: ${getSearchModeLabel(mode)})`}
                        style={modeSwitchStyle}
                    >
                        {getSearchModeLabel(mode)}
                    </button>
                    <input
                        value={activeQuery}
                        onChange={(event) => {
                            if (mode === "present") {
                                setQuery(event.target.value);
                            } else if (mode === "history") {
                                setHistoricalQuery(event.target.value);
                            } else {
                                setWikiQuery(event.target.value);
                            }
                            setIsOpen(true);
                        }}
                        onFocus={() => setIsOpen(true)}
                        onKeyDown={(event) => {
                            if (event.key === "Escape") {
                                setIsOpen(false);
                                return;
                            }
                            if (event.key === "Enter") {
                                if (mode === "present" && results[0]) {
                                    event.preventDefault();
                                    void selectPrediction(results[0]);
                                }
                                if (mode === "history" && historicalResults[0]) {
                                    event.preventDefault();
                                    selectHistoricalEntity(historicalResults[0]);
                                }
                                if (mode === "wiki" && wikiResults[0]) {
                                    event.preventDefault();
                                    selectWiki(wikiResults[0]);
                                }
                            }
                        }}
                        disabled={mode === "present" && !hasApiKey}
                        placeholder={
                            mode === "present"
                                ? "Tìm địa điểm hiện tại"
                                : mode === "history"
                                    ? "Tìm thực thể lịch sử"
                                    : "Tìm bài viết wiki"
                        }
                        style={inputStyle}
                    />
                    {activeQuery || focusedPlace ? (
                        <button
                            type="button"
                            onClick={clearSearch}
                            title="Xóa tìm kiếm"
                            aria-label="Xóa ô tìm kiếm"
                            style={clearButtonStyle}
                        >
                            x
                        </button>
                    ) : null}
                </div>
            </div>

            {isOpen && shouldRenderResults(mode, activeQuery, activeLoading, activeError, results, historicalResults, wikiResults) ? (
                <div style={resultsPanelStyle}>
                    {mode === "present" ? (
                        <PresentResults
                            isLoading={isLoading}
                            error={error}
                            query={query}
                            results={results}
                            selectingPlaceId={selectingPlaceId}
                            onSelect={selectPrediction}
                        />
                    ) : mode === "history" ? (
                        <HistoricalResults
                            isLoading={isHistoricalLoading}
                            error={historicalError}
                            query={historicalQuery}
                            results={historicalResults}
                            expandedEntityId={expandedEntityId}
                            adminLabels={adminLabels}
                            selectingGeometryId={selectingGeometryId}
                            hasApiKey={hasApiKey}
                            onSelectEntity={selectHistoricalEntity}
                            onSelectGeometry={selectHistoricalGeometry}
                        />
                    ) : (
                        <WikiResults
                            isLoading={isWikiLoading}
                            error={wikiError}
                            query={wikiQuery}
                            results={wikiResults}
                            onSelect={selectWiki}
                        />
                    )}
                </div>
            ) : null}
        </div>
    );
}

function PresentResults({
    isLoading,
    error,
    query,
    results,
    selectingPlaceId,
    onSelect,
}: {
    isLoading: boolean;
    error: string | null;
    query: string;
    results: PresentPlacePrediction[];
    selectingPlaceId: string | null;
    onSelect: (prediction: PresentPlacePrediction) => Promise<void>;
}) {
    if (isLoading) return <div style={statusStyle}>Đang tìm...</div>;
    if (error) return <div style={{ ...statusStyle, color: "#fecaca" }}>{error}</div>;
    if (!results.length && query.trim().length >= 2) return <div style={statusStyle}>Không có kết quả.</div>;

    return (
        <>
            {results.map((result) => (
                <button
                    key={result.placeId}
                    type="button"
                    onClick={() => void onSelect(result)}
                    disabled={selectingPlaceId === result.placeId}
                    style={{
                        ...resultButtonStyle,
                        cursor: selectingPlaceId === result.placeId ? "wait" : "pointer",
                    }}
                    onMouseEnter={(event) => {
                        event.currentTarget.style.background = "rgba(56, 189, 248, 0.1)";
                    }}
                    onMouseLeave={(event) => {
                        event.currentTarget.style.background = "transparent";
                    }}
                >
                    <span style={primaryResultTextStyle}>{result.mainText}</span>
                    <span style={secondaryResultTextStyle}>{result.secondaryText || result.description}</span>
                </button>
            ))}
        </>
    );
}

function HistoricalResults({
    isLoading,
    error,
    query,
    results,
    expandedEntityId,
    adminLabels,
    selectingGeometryId,
    hasApiKey,
    onSelectEntity,
    onSelectGeometry,
}: {
    isLoading: boolean;
    error: string | null;
    query: string;
    results: EntityGeometriesSearchItem[];
    expandedEntityId: string | null;
    adminLabels: Record<string, AdminLabelState>;
    selectingGeometryId: string | null;
    hasApiKey: boolean;
    onSelectEntity: (item: EntityGeometriesSearchItem) => void;
    onSelectGeometry: (item: EntityGeometriesSearchItem, geometry: EntityGeometrySearchGeo) => void;
}) {
    if (isLoading) return <div style={statusStyle}>Đang tìm thực thể...</div>;
    if (error) return <div style={{ ...statusStyle, color: "#fecaca" }}>{error}</div>;
    if (!results.length && query.trim().length >= 2) return <div style={statusStyle}>Không có thực thể phù hợp.</div>;

    return (
        <>
            {results.map((item) => {
                const isExpanded = expandedEntityId === item.entity_id;
                return (
                    <div key={item.entity_id} style={{ borderBottom: "1px solid rgba(148, 163, 184, 0.12)" }}>
                        <button
                            type="button"
                            onClick={() => onSelectEntity(item)}
                            disabled={!item.geometries.length}
                            style={{
                                ...resultButtonStyle,
                                cursor: item.geometries.length ? "pointer" : "not-allowed",
                            }}
                            onMouseEnter={(event) => {
                                if (item.geometries.length) event.currentTarget.style.background = "rgba(56, 189, 248, 0.1)";
                            }}
                            onMouseLeave={(event) => {
                                event.currentTarget.style.background = "transparent";
                            }}
                        >
                            <span style={primaryResultTextStyle}>{item.name || item.entity_id}</span>
                            <span style={secondaryResultTextStyle}>
                                {item.geometries.length
                                    ? `${item.geometries.length} hình bản đồ`
                                    : "Không có hình bản đồ"}
                                {item.description ? ` · ${item.description}` : ""}
                            </span>
                        </button>
                        {isExpanded ? (
                            <div style={{ padding: "0 8px 8px", display: "grid", gap: 6 }}>
                                {!hasApiKey ? (
                                    <div style={{ ...statusStyle, padding: "7px 8px" }}>
                                        Thiếu SEARCH_MAP_API_KEY để lấy địa danh hiện tại.
                                    </div>
                                ) : null}
                                {item.geometries.map((geometry) => (
                                    <button
                                        key={geometry.id}
                                        type="button"
                                        onClick={() => onSelectGeometry(item, geometry)}
                                        disabled={selectingGeometryId === geometry.id}
                                        style={{
                                            border: "1px solid rgba(148, 163, 184, 0.16)",
                                            borderRadius: 8,
                                            background: "rgba(15, 23, 42, 0.68)",
                                            color: "#e2e8f0",
                                            padding: "8px 9px",
                                            textAlign: "left",
                                            cursor: selectingGeometryId === geometry.id ? "wait" : "pointer",
                                        }}
                                    >
                                        <span style={{ ...primaryResultTextStyle, fontSize: 12 }}>
                                            {formatAdminLabel(adminLabels[geometry.id])}
                                        </span>
                                        <span style={{ ...secondaryResultTextStyle, marginTop: 3 }}>
                                            {formatGeometryMeta(geometry)}
                                        </span>
                                    </button>
                                ))}
                            </div>
                        ) : null}
                    </div>
                );
            })}
        </>
    );
}

function WikiResults({
    isLoading,
    error,
    query,
    results,
    onSelect,
}: {
    isLoading: boolean;
    error: string | null;
    query: string;
    results: Wiki[];
    onSelect: (wiki: Wiki) => void;
}) {
    if (isLoading) return <div style={statusStyle}>Đang tìm wiki...</div>;
    if (error) return <div style={{ ...statusStyle, color: "#fecaca" }}>{error}</div>;
    if (!results.length && query.trim().length >= 2) return <div style={statusStyle}>Không tìm thấy bài viết.</div>;

    return (
        <>
            {results.map((wiki) => (
                <button
                    key={wiki.id}
                    type="button"
                    onClick={() => onSelect(wiki)}
                    style={resultButtonStyle}
                    onMouseEnter={(event) => {
                        event.currentTarget.style.background = "rgba(56, 189, 248, 0.1)";
                    }}
                    onMouseLeave={(event) => {
                        event.currentTarget.style.background = "transparent";
                    }}
                >
                    <span style={primaryResultTextStyle}>{wiki.title || wiki.slug || "Không có tiêu đề"}</span>
                    {wiki.slug && (
                        <span style={secondaryResultTextStyle}>/wiki/{wiki.slug}</span>
                    )}
                </button>
            ))}
        </>
    );
}

function shouldRenderResults(
    mode: SearchMode,
    query: string,
    isLoading: boolean,
    error: string | null,
    presentResults: PresentPlacePrediction[],
    historicalResults: EntityGeometriesSearchItem[],
    wikiResults: Wiki[]
): boolean {
    if (isLoading || error || query.trim().length >= 2) return true;
    if (mode === "present") return presentResults.length > 0;
    if (mode === "history") return historicalResults.length > 0;
    return wikiResults.length > 0;
}

function formatAdminLabel(state: AdminLabelState | undefined): string {
    if (!state || state.status === "loading") return "Đang lấy địa danh hiện tại...";
    if (state.status === "error") return "Không lấy được địa danh hiện tại";
    return state.label || state.address || "Địa danh hiện tại không rõ";
}

function formatGeometryMeta(geometry: EntityGeometrySearchGeo): string {
    const type = geometry.type || "hình bản đồ";
    const timeStart = geometry.time_start ?? null;
    const timeEnd = geometry.time_end ?? null;
    const time =
        timeStart !== null && timeEnd !== null
            ? `${timeStart} - ${timeEnd}`
            : timeStart !== null
                ? `từ ${timeStart}`
                : timeEnd !== null
                    ? `đến ${timeEnd}`
                    : "không rõ thời gian";
    return `${type} · ${time}`;
}

const searchCardStyle = {
    border: "1px solid rgba(148, 163, 184, 0.28)",
    borderRadius: 10,
    background: "rgba(15, 23, 42, 0.92)",
    boxShadow: "0 16px 36px rgba(2, 6, 23, 0.35)",
    color: "#e2e8f0",
    overflow: "hidden",
    backdropFilter: "blur(6px)",
} satisfies CSSProperties;

const searchInputRowStyle = {
    display: "flex",
    alignItems: "center",
    gap: 8,
    padding: "9px 10px",
} satisfies CSSProperties;

const inputStyle = {
    flex: 1,
    minWidth: 0,
    border: "none",
    outline: "none",
    background: "transparent",
    color: "#f8fafc",
    fontSize: 13,
    fontWeight: 700,
} satisfies CSSProperties;

const modeSwitchStyle = {
    border: "none",
    borderRight: "1px solid rgba(148, 163, 184, 0.22)",
    background: "transparent",
    color: "#38bdf8",
    padding: "0 10px 0 0",
    fontSize: 11,
    fontWeight: 900,
    cursor: "pointer",
    lineHeight: 1,
} satisfies CSSProperties;

const clearButtonStyle = {
    width: 26,
    height: 26,
    border: "1px solid rgba(148, 163, 184, 0.28)",
    borderRadius: 6,
    background: "rgba(15, 23, 42, 0.74)",
    color: "#cbd5e1",
    cursor: "pointer",
    fontWeight: 900,
} satisfies CSSProperties;

const resultsPanelStyle = {
    marginTop: 8,
    overflow: "hidden",
    border: "1px solid rgba(148, 163, 184, 0.24)",
    borderRadius: 10,
    background: "rgba(15, 23, 42, 0.96)",
    boxShadow: "0 16px 36px rgba(2, 6, 23, 0.4)",
    color: "#e2e8f0",
    backdropFilter: "blur(6px)",
} satisfies CSSProperties;

const resultButtonStyle = {
    display: "grid",
    gap: 3,
    width: "100%",
    padding: "10px 12px",
    border: "none",
    background: "transparent",
    color: "#e2e8f0",
    textAlign: "left",
} satisfies CSSProperties;

const primaryResultTextStyle = {
    display: "block",
    fontSize: 13,
    fontWeight: 900,
    overflowWrap: "anywhere",
} satisfies CSSProperties;

const secondaryResultTextStyle = {
    display: "block",
    fontSize: 11,
    color: "#94a3b8",
    lineHeight: 1.35,
    overflowWrap: "anywhere",
} satisfies CSSProperties;

const statusStyle = {
    padding: "11px 12px",
    color: "#94a3b8",
    fontSize: 12,
    fontWeight: 700,
} satisfies CSSProperties;

function getSearchModeLabel(mode: SearchMode): string {
    if (mode === "present") return "Hiện tại";
    if (mode === "history") return "Lịch sử";
    return "Wiki";
}
