import SearchOutlined from "@mui/icons-material/SearchOutlined";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import {
    AdminFilterResetButton,
    AdminFilterSelect,
    AdminListToolbar,
    AdminSearchBox,
} from "@/shared/ui/AdminListLayout.jsx";
import { Button } from "@/shared/ui/Button.jsx";
import { DataState } from "@/shared/ui/DataState.jsx";
import { DataTable } from "@/shared/ui/DataTable.jsx";
import { fetchLuckyGiftUserProfile, fetchLuckyGiftUserProfiles } from "../api.js";
import { UserProfileDetail } from "./UserProfileDetail.jsx";
import { buildUserProfileColumns } from "./UserProfileTable.jsx";

const PAGE_SIZE = 20;
const IDENTITY_OPTIONS = [
    ["all", "全部用户"],
    ["internal", "内部用户"],
    ["external", "外部接入用户"],
];
const STAGE_OPTIONS = [
    ["", "全部最近开奖阶段"],
    ["novice", "最近为新手阶段"],
    ["normal", "最近为普通阶段"],
    ["advanced", "最近为高阶阶段"],
];
const STATUS_OPTIONS = [
    ["", "全部状态"],
    ["jackpot", "中出过大奖"],
    ["loss_streak", "连续未中奖"],
    ["pending_token", "有待兑消费大奖"],
];
const SORT_OPTIONS = [
    ["last_draw_at", "最近抽奖"],
    ["lifetime_rtp", "累计 RTP"],
    ["lifetime_wager", "累计消耗"],
    ["lifetime_payout", "累计返奖"],
    ["jackpot_count", "大奖次数"],
    ["loss_streak", "连续未中奖"],
];
const SORT_DIRECTION_OPTIONS = [
    ["desc", "从高到低 / 从新到旧"],
    ["asc", "从低到高 / 从旧到新"],
];

export function UserProfilesView({ apps, defaultAppCode, poolIDsByApp, refreshKey = 0 }) {
    const [appCode, setAppCode] = useState(defaultAppCode);
    const [poolId, setPoolId] = useState("");
    const [identityType, setIdentityType] = useState("all");
    const [stage, setStage] = useState("");
    const [status, setStatus] = useState("");
    const [sortBy, setSortBy] = useState("last_draw_at");
    const [sortDirection, setSortDirection] = useState("desc");
    const [keywordDraft, setKeywordDraft] = useState("");
    const [keyword, setKeyword] = useState("");
    const [page, setPage] = useState(1);
    const [reloadKey, setReloadKey] = useState(0);
    const [expandedKey, setExpandedKey] = useState("");
    const [details, setDetails] = useState({});
    const handledRefreshKey = useRef(refreshKey);
    // 页码只负责兼容通用 DataTable 的滚动触发；真正翻页使用 owner 返回的不可解释 cursor，
    // 因此并发开奖插入新画像时不会因为 OFFSET 位移而把同一用户追加两次。
    const cursorsByPage = useRef({ 1: "" });
    const [state, setState] = useState({
        error: "",
        hasMore: false,
        items: [],
        loading: false,
        snapshotAtMs: 0,
        total: 0,
    });

    const appOptions = useMemo(
        () =>
            apps.map((item) => [
                item.app_code ?? item.appCode,
                `${item.app_name ?? item.appName ?? ""} (${item.app_code ?? item.appCode})`,
            ]),
        [apps],
    );
    const poolIDs = useMemo(() => poolIDsByApp.get(appCode) || [], [appCode, poolIDsByApp]);
    const poolOptions = useMemo(() => poolIDs.map((value) => [value, value]), [poolIDs]);

    useEffect(() => {
        setAppCode((current) => current || defaultAppCode);
    }, [defaultAppCode]);

    useEffect(() => {
        // 奖池是画像聚合主键的一部分。应用切换或配置刚发布后若当前奖池不再存在，自动落到该应用第一口池，
        // 不带空 pool_id 请求，避免后端退化成跨池扫描并把两个独立奖池的用户数据混在一起。
        setPoolId((current) => (current && poolIDs.includes(current) ? current : poolIDs[0] || ""));
    }, [poolIDs]);

    useEffect(() => {
        if (!appCode || !poolId) {
            setState({
                error: "",
                hasMore: false,
                items: [],
                loading: false,
                snapshotAtMs: 0,
                total: 0,
            });
            return undefined;
        }
        let cancelled = false;
        setState((current) => ({ ...current, error: "", loading: true }));
        fetchLuckyGiftUserProfiles({
            appCode,
            cursor: page > 1 ? cursorsByPage.current[page] || "" : "",
            identityType,
            keyword,
            page,
            pageSize: PAGE_SIZE,
            poolId,
            sortBy,
            sortDirection,
            stage,
            status,
        })
            .then((result) => {
                if (cancelled) {
                    return;
                }
                if (result.hasMore && result.nextCursor) {
                    cursorsByPage.current[page + 1] = result.nextCursor;
                } else {
                    delete cursorsByPage.current[page + 1];
                }
                setState((current) => ({
                    error: "",
                    hasMore: result.hasMore && Boolean(result.nextCursor),
                    // cursor 保证顺序稳定，前端仍按身份键防御性去重，避免故障代理重复响应污染 React row key。
                    items: page > 1 ? mergeProfiles(current.items, result.items) : result.items,
                    loading: false,
                    snapshotAtMs: result.snapshotAtMs,
                    total: result.total,
                }));
            })
            .catch((error) => {
                if (cancelled) {
                    return;
                }
                setState((current) => ({
                    ...current,
                    error: error.message || "获取用户画像失败",
                    loading: false,
                }));
            });
        return () => {
            cancelled = true;
        };
    }, [appCode, identityType, keyword, page, poolId, reloadKey, sortBy, sortDirection, stage, status]);

    const resetQueryState = useCallback(() => {
        cursorsByPage.current = { 1: "" };
        setPage(1);
        setExpandedKey("");
        setDetails({});
    }, []);

    const reloadProfiles = useCallback(() => {
        cursorsByPage.current = { 1: "" };
        setPage(1);
        setExpandedKey("");
        setDetails({});
        setReloadKey((current) => current + 1);
    }, []);

    useEffect(() => {
        if (handledRefreshKey.current === refreshKey) {
            return;
        }
        handledRefreshKey.current = refreshKey;
        // 顶部刷新只重建游标和当前结果，筛选与已提交关键词继续由本组件状态持有，
        // 避免通过 React key 重挂载整页后把运营正在排查的条件恢复成默认值。
        reloadProfiles();
    }, [refreshKey, reloadProfiles]);

    const changeAppCode = useCallback(
        (nextAppCode) => {
            setAppCode(nextAppCode);
            setPoolId((poolIDsByApp.get(nextAppCode) || [])[0] || "");
            resetQueryState();
        },
        [poolIDsByApp, resetQueryState],
    );

    const changePoolId = useCallback(
        (nextPoolId) => {
            setPoolId(nextPoolId);
            resetQueryState();
        },
        [resetQueryState],
    );

    const changeIdentityType = useCallback(
        (nextIdentityType) => {
            setIdentityType(nextIdentityType);
            setKeywordDraft("");
            setKeyword("");
            resetQueryState();
        },
        [resetQueryState],
    );

    const submitSearch = useCallback(
        (event) => {
            event.preventDefault();
            setKeyword(keywordDraft.trim());
            resetQueryState();
        },
        [keywordDraft, resetQueryState],
    );

    const resetFilters = useCallback(() => {
        setIdentityType("all");
        setStage("");
        setStatus("");
        setSortBy("last_draw_at");
        setSortDirection("desc");
        setKeywordDraft("");
        setKeyword("");
        resetQueryState();
    }, [resetQueryState]);

    const loadDetail = useCallback(async (profile, jackpotCursor = "", append = false) => {
        const key = profile.key;
        setDetails((current) => ({
            ...current,
            [key]: {
                data: current[key]?.data,
                error: "",
                loading: !append,
                loadingMore: append,
            },
        }));
        try {
            const data = await fetchLuckyGiftUserProfile({
                appCode: profile.appCode,
                externalUserId: profile.externalUserId,
                identityType: profile.identityType,
                jackpotCursor,
                poolId: profile.poolId,
                userId: profile.user.userId,
            });
            setDetails((current) => {
                const previous = current[key]?.data;
                const nextData =
                    append && previous
                        ? {
                              ...data,
                              // owner cursor 已固定在最后一条大奖事实之后；前端再按事实键去重，防止代理重放响应，
                              // 同时不吞掉 request_id 为空的历史记录。
                              jackpotHits: mergeJackpotHits(previous.jackpotHits, data.jackpotHits),
                              multiplierDistribution: previous.multiplierDistribution,
                              profile: previous.profile,
                          }
                        : data;
                return { ...current, [key]: { data: nextData, error: "", loading: false, loadingMore: false } };
            });
        } catch (error) {
            setDetails((current) => ({
                ...current,
                [key]: {
                    data: current[key]?.data,
                    error: error.message || "获取画像明细失败",
                    loading: false,
                    loadingMore: false,
                },
            }));
        }
    }, []);

    const loadMoreDetail = useCallback(
        (profile) => {
            const detail = details[profile.key]?.data;
            if (!detail?.jackpotHasMore || !detail.nextJackpotCursor) {
                return;
            }
            loadDetail(profile, detail.nextJackpotCursor, true);
        },
        [details, loadDetail],
    );

    const toggleProfile = useCallback(
        (profile) => {
            if (expandedKey === profile.key) {
                setExpandedKey("");
                return;
            }
            setExpandedKey(profile.key);
            if (!details[profile.key]?.data && !details[profile.key]?.loading) {
                loadDetail(profile);
            }
        },
        [details, expandedKey, loadDetail],
    );

    const columns = useMemo(() => buildUserProfileColumns(expandedKey), [expandedKey]);
    const loadMoreProfiles = useCallback(() => {
        if (!state.loading && state.hasMore) {
            setPage((current) => current + 1);
        }
    }, [state.hasMore, state.loading]);
    const hasActiveFilters =
        identityType !== "all" ||
        Boolean(stage || status || keywordDraft || keyword) ||
        sortBy !== "last_draw_at" ||
        sortDirection !== "desc";
    const searchPlaceholder =
        identityType === "external"
            ? "只支持 external_user_id"
            : identityType === "internal"
              ? "短号 / 长号 / 靓号"
              : "短号 / 长号 / 靓号 / external_user_id";

    return (
        <div className="ops-view ops-user-profiles">
            <AdminListToolbar
                filters={
                    <>
                        <AdminFilterSelect label="应用" options={appOptions} value={appCode} onChange={changeAppCode} />
                        <AdminFilterSelect label="奖池" options={poolOptions} value={poolId} onChange={changePoolId} />
                        <AdminFilterSelect
                            label="用户来源"
                            options={IDENTITY_OPTIONS}
                            value={identityType}
                            onChange={changeIdentityType}
                        />
                        <AdminFilterSelect
                            label="最近开奖阶段"
                            options={STAGE_OPTIONS}
                            value={stage}
                            onChange={(value) => {
                                setStage(value);
                                resetQueryState();
                            }}
                        />
                        <AdminFilterSelect
                            label="问题定位"
                            options={STATUS_OPTIONS}
                            value={status}
                            onChange={(value) => {
                                setStatus(value);
                                resetQueryState();
                            }}
                        />
                        <AdminFilterSelect
                            label="排序指标"
                            options={SORT_OPTIONS}
                            value={sortBy}
                            onChange={(value) => {
                                setSortBy(value);
                                resetQueryState();
                            }}
                        />
                        <AdminFilterSelect
                            label="排序方向"
                            options={SORT_DIRECTION_OPTIONS}
                            value={sortDirection}
                            onChange={(value) => {
                                setSortDirection(value);
                                resetQueryState();
                            }}
                        />
                        <form className="ops-user-profile-search" onSubmit={submitSearch}>
                            <AdminSearchBox
                                label="用户"
                                placeholder={searchPlaceholder}
                                value={keywordDraft}
                                onChange={setKeywordDraft}
                            />
                            <Button startIcon={<SearchOutlined fontSize="small" />} type="submit" variant="primary">
                                查询
                            </Button>
                        </form>
                        <AdminFilterResetButton disabled={!hasActiveFilters} onClick={resetFilters} />
                    </>
                }
            />
            {state.error && state.items.length ? (
                <div className="ops-alert" role="alert">
                    <span>{state.error}</span>
                    <Button size="small" onClick={reloadProfiles}>
                        重新加载
                    </Button>
                </div>
            ) : null}
            <DataState
                error={state.items.length ? "" : state.error}
                loading={state.loading && !state.items.length}
                onRetry={reloadProfiles}
            >
                <DataTable
                    className="ops-user-profile-table"
                    columns={columns}
                    emptyLabel="当前无数据"
                    getRowProps={(profile) => ({
                        "aria-expanded": expandedKey === profile.key,
                        className:
                            expandedKey === profile.key ? "ops-user-profile-row is-expanded" : "ops-user-profile-row",
                        role: "button",
                        tabIndex: 0,
                        onClick: () => toggleProfile(profile),
                        onKeyDown: (event) => {
                            if (event.key !== "Enter" && event.key !== " ") {
                                return;
                            }
                            event.preventDefault();
                            toggleProfile(profile);
                        },
                    })}
                    items={state.items}
                    infiniteScroll={{
                        doneLabel: state.items.length ? "已加载全部用户" : "",
                        hasMore: !state.error && state.hasMore,
                        loading: state.loading && state.items.length > 0,
                        onLoadMore: loadMoreProfiles,
                    }}
                    minWidth="1830px"
                    renderRowDetail={(profile) =>
                        expandedKey === profile.key ? (
                            <UserProfileDetail
                                detailState={details[profile.key]}
                                key={`${profile.key}:detail`}
                                onLoadMore={() => loadMoreDetail(profile)}
                                profile={profile}
                                onRetry={() => loadDetail(profile)}
                            />
                        ) : null
                    }
                    rowKey={(profile) => profile.key}
                    tableClassName="ops-user-profile-grid"
                    title={`${appCode || "-"} / ${poolId || "-"} 用户画像${state.loading ? "（更新中）" : ""}`}
                    total={state.total}
                />
            </DataState>
        </div>
    );
}

function mergeProfiles(previous = [], next = []) {
    const byKey = new Map(previous.map((profile) => [profile.key, profile]));
    next.forEach((profile) => byKey.set(profile.key, profile));
    return [...byKey.values()];
}

function mergeJackpotHits(previous = [], next = []) {
    const seen = new Set(previous.map(jackpotEventKey));
    return [
        ...previous,
        ...next.filter((hit) => {
            const key = jackpotEventKey(hit);
            if (seen.has(key)) {
                return false;
            }
            seen.add(key);
            return true;
        }),
    ];
}

function jackpotEventKey(hit) {
    return hit.eventKey || `${hit.drawId}:${hit.requestId}:${hit.occurredAtMs}:${hit.mechanism}`;
}
