import { useCallback, useEffect, useMemo, useState } from "react";
import Dialog from "@mui/material/Dialog";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import {
    approveFinanceApplication,
    approveFinanceWithdrawalApplication,
    createFinanceApplication,
    createFinanceCoinSellerRechargeOrder,
    exportFinanceRechargeBills,
    fetchFinanceApplicationOptions,
    fetchFinanceRechargeApps,
    fetchFinanceRechargeOverview,
    fetchFinanceRechargeSummaries,
    fetchFinanceSession,
    filterOperationsByPermissions,
    grantFinanceCoinSellerRechargeOrder,
    listFinanceApplications,
    listFinanceCoinSellerRechargeOrders,
    listFinanceRechargeDetails,
    listFinanceRechargeRegions,
    listMyFinanceApplications,
    listFinanceWithdrawalApplications,
    refreshFinanceGoogleRechargePaid,
    rejectFinanceApplication,
    rejectFinanceWithdrawalApplication,
    verifyFinanceCoinSellerRechargeReceipt,
    verifyFinanceCoinSellerRechargeOrder,
} from "./api.js";
import { FinanceApplicationForm } from "./components/FinanceApplicationForm.jsx";
import { FinanceApplicationList } from "./components/FinanceApplicationList.jsx";
import { FinanceAuditDialog } from "./components/FinanceAuditDialog.jsx";
import { FinanceCoinSellerRechargeOrderList } from "./components/FinanceCoinSellerRechargeOrderList.jsx";
import { FinanceMyApplicationList } from "./components/FinanceMyApplicationList.jsx";
import { FinanceOverview } from "./components/FinanceOverview.jsx";
import { FinanceReconciliation } from "./components/FinanceReconciliation.jsx";
import { FinanceRechargeDetailList } from "./components/FinanceRechargeDetailList.jsx";
import { FinanceShell } from "./components/FinanceShell.jsx";
import { FinanceWithdrawalApplicationList } from "./components/FinanceWithdrawalApplicationList.jsx";
import { DEFAULT_APPLICATION_FORM } from "./constants.js";
import {
    EMPTY_RECHARGE_OVERVIEW,
    EMPTY_RECHARGE_SUMMARY,
    buildApplicationPayload,
    validateApplicationPayload,
} from "./format.js";
import { downloadCsv } from "@/shared/api/download";
import { TimeRangeFilter } from "@/shared/ui/TimeRangeFilter.jsx";
import { useToast } from "@/shared/ui/ToastProvider.jsx";

const emptyOptions = { apps: [], operations: [], walletIdentities: [] };
const pageSize = 50;
const DAY_MS = 86_400_000;
const CHINA_OFFSET_MS = 8 * 3_600_000;
const FINANCE_VIEWS = new Set(["overview", "rechargeDetails", "recon"]);

function chinaDayStart(timestamp) {
    return Math.floor((timestamp + CHINA_OFFSET_MS) / DAY_MS) * DAY_MS - CHINA_OFFSET_MS;
}

function timePresets() {
    const now = Date.now();
    const todayStart = chinaDayStart(now);
    const chinaNow = new Date(now + CHINA_OFFSET_MS);
    const monthStart = Date.UTC(chinaNow.getUTCFullYear(), chinaNow.getUTCMonth(), 1) - CHINA_OFFSET_MS;
    return [
        { key: "today", label: "今天", range: { endMs: todayStart + DAY_MS, startMs: todayStart } },
        { key: "7d", label: "近7天", range: { endMs: todayStart + DAY_MS, startMs: todayStart - 6 * DAY_MS } },
        { key: "30d", label: "近30天", range: { endMs: todayStart + DAY_MS, startMs: todayStart - 29 * DAY_MS } },
        { key: "month", label: "本月", range: { endMs: todayStart + DAY_MS, startMs: monthStart } },
        { key: "all", label: "不限", range: { endMs: "", startMs: "" } },
    ];
}

function reconMonthMeta(offset) {
    const chinaNow = new Date(Date.now() + CHINA_OFFSET_MS);
    const year = chinaNow.getUTCFullYear();
    const month = chinaNow.getUTCMonth() + offset;
    const startMs = Date.UTC(year, month, 1) - CHINA_OFFSET_MS;
    const endMs = Date.UTC(year, month + 1, 1) - CHINA_OFFSET_MS;
    const startDate = new Date(startMs + CHINA_OFFSET_MS);
    return {
        endMs,
        isCurrent: offset === 0,
        label: `${startDate.getUTCFullYear()}年${startDate.getUTCMonth() + 1}月`,
        startMs,
    };
}

export function FinanceApp() {
    const { showToast } = useToast();
    const [sessionState, setSessionState] = useState({ error: "", loading: true, session: null });
    const [optionsState, setOptionsState] = useState({ data: emptyOptions, error: "", loading: false });
    const [rechargeDetailsState, setRechargeDetailsState] = useState({
        data: { items: [], page: 1, pageSize, total: 0 },
        error: "",
        loading: false,
    });
    const [rechargeSummaryState, setRechargeSummaryState] = useState({
        merged: EMPTY_RECHARGE_SUMMARY,
        loading: false,
        perApp: [],
        prev: null,
    });
    const [rechargeOverviewState, setRechargeOverviewState] = useState({
        data: EMPTY_RECHARGE_OVERVIEW,
        loading: false,
    });
    const [rechargeRegionsState, setRechargeRegionsState] = useState({ byApp: {}, loading: false });
    const [rechargeAppsState, setRechargeAppsState] = useState({ items: [], loaded: false });
    const [googlePaidRefreshing, setGooglePaidRefreshing] = useState(false);
    const [reconMonthOffset, setReconMonthOffset] = useState(0);
    const [reconState, setReconState] = useState({
        loading: false,
        overview: EMPTY_RECHARGE_OVERVIEW,
        summary: EMPTY_RECHARGE_SUMMARY,
    });
    const [myApplicationsState, setMyApplicationsState] = useState({
        data: { items: [], page: 1, pageSize, total: 0 },
        error: "",
        loading: false,
    });
    const [applicationsState, setApplicationsState] = useState({
        data: { items: [], page: 1, pageSize, total: 0 },
        error: "",
        loading: false,
    });
    const [withdrawalsState, setWithdrawalsState] = useState({
        data: { items: [], page: 1, pageSize, total: 0 },
        error: "",
        loading: false,
    });
    const [coinSellerRechargeOrdersState, setCoinSellerRechargeOrdersState] = useState({
        data: { items: [], page: 1, pageSize, total: 0 },
        error: "",
        loading: false,
    });
    const [coinSellerRechargeOrderActionLoading, setCoinSellerRechargeOrderActionLoading] = useState("");
    const [activeView, setActiveView] = useState("create");
    const [rechargeDetailFilters, setRechargeDetailFilters] = useState(() => ({
        appCode: "",
        currency: "usd",
        keyword: "",
        page: 1,
        paidState: "",
        rechargeType: "",
        regionId: "",
        timeRange: timePresets().find((preset) => preset.key === "30d").range,
    }));
    const [rechargeExporting, setRechargeExporting] = useState(false);
    const [myFilters, setMyFilters] = useState({ appCode: "", keyword: "", operation: "", page: 1, status: "" });
    const [filters, setFilters] = useState({ appCode: "", keyword: "", operation: "", page: 1, status: "pending" });
    const [withdrawalFilters, setWithdrawalFilters] = useState({ appCode: "", keyword: "", page: 1 });
    const [coinSellerRechargeOrderFilters, setCoinSellerRechargeOrderFilters] = useState({
        appCode: "",
        grantStatus: "",
        keyword: "",
        page: 1,
        providerCode: "",
        status: "",
        verifyStatus: "",
    });
    const [form, setForm] = useState(DEFAULT_APPLICATION_FORM);
    const [createDialogOpen, setCreateDialogOpen] = useState(false);
    const [submitting, setSubmitting] = useState(false);
    const [auditTarget, setAuditTarget] = useState(null);
    const [auditLoading, setAuditLoading] = useState(false);
    const [withdrawalAuditTarget, setWithdrawalAuditTarget] = useState(null);
    const [withdrawalAuditLoading, setWithdrawalAuditLoading] = useState(false);

    useEffect(() => {
        let mounted = true;
        fetchFinanceSession()
            .then((session) => {
                if (!mounted) {
                    return;
                }
                setSessionState({ error: "", loading: false, session });
                setActiveView(
                    session.canViewAppRechargeDetails
                        ? "overview"
                        : session.canViewCoinSellerRechargeOrders
                          ? "coinSellerRechargeOrders"
                          : session.canAuditApplication
                            ? "applications"
                            : session.canCreateApplication
                              ? "create"
                              : "withdrawals",
                );
            })
            .catch((err) => {
                if (mounted) {
                    setSessionState({ error: err.message || "登录已失效", loading: false, session: null });
                }
            });
        return () => {
            mounted = false;
        };
    }, []);

    const session = sessionState.session;
    const canLoadOptions = Boolean(session?.canAccessFinance);
    const canViewFinance = Boolean(session?.canViewAppRechargeDetails);

    // 财务三页（概览/流水/对账）共享同一套 App × 时间 × 计价 全局筛选。
    const rechargeBaseQuery = useMemo(
        () => ({
            app_code: rechargeDetailFilters.appCode,
            end_at_ms: rechargeDetailFilters.timeRange.endMs,
            keyword: rechargeDetailFilters.keyword,
            recharge_type: rechargeDetailFilters.rechargeType,
            region_id: rechargeDetailFilters.appCode ? rechargeDetailFilters.regionId : "",
            start_at_ms: rechargeDetailFilters.timeRange.startMs,
            stat_tz: "Asia/Shanghai",
            status: "succeeded",
        }),
        [rechargeDetailFilters],
    );
    const rechargeDetailQuery = useMemo(
        () => ({
            ...rechargeBaseQuery,
            page: rechargeDetailFilters.page,
            page_size: pageSize,
            paid_state: rechargeDetailFilters.paidState,
        }),
        [rechargeBaseQuery, rechargeDetailFilters.page, rechargeDetailFilters.paidState],
    );
    const myApplicationQuery = useMemo(
        () => ({
            app_code: myFilters.appCode,
            keyword: myFilters.keyword,
            operation: myFilters.operation,
            page: myFilters.page,
            page_size: pageSize,
            status: myFilters.status,
        }),
        [myFilters],
    );
    const applicationQuery = useMemo(
        () => ({
            app_code: filters.appCode,
            keyword: filters.keyword,
            operation: filters.operation,
            page: filters.page,
            page_size: pageSize,
            status: filters.status,
        }),
        [filters],
    );
    const withdrawalQuery = useMemo(
        () => ({
            app_code: withdrawalFilters.appCode,
            keyword: withdrawalFilters.keyword,
            page: withdrawalFilters.page,
            page_size: pageSize,
        }),
        [withdrawalFilters],
    );
    const coinSellerRechargeOrderQuery = useMemo(
        () => ({
            app_code: coinSellerRechargeOrderFilters.appCode,
            grant_status: coinSellerRechargeOrderFilters.grantStatus,
            keyword: coinSellerRechargeOrderFilters.keyword,
            page: coinSellerRechargeOrderFilters.page,
            page_size: pageSize,
            provider_code: coinSellerRechargeOrderFilters.providerCode,
            status: coinSellerRechargeOrderFilters.status,
            verify_status: coinSellerRechargeOrderFilters.verifyStatus,
        }),
        [coinSellerRechargeOrderFilters],
    );

    const loadOptions = useCallback(async () => {
        if (!canLoadOptions) {
            return;
        }
        setOptionsState((current) => ({ ...current, error: "", loading: true }));
        try {
            const data = await fetchFinanceApplicationOptions();
            setOptionsState({ data, error: "", loading: false });
        } catch (err) {
            setOptionsState({ data: emptyOptions, error: err.message || "加载财务选项失败", loading: false });
        }
    }, [canLoadOptions]);

    const loadMyApplications = useCallback(async () => {
        if (!session?.canCreateApplication) {
            return;
        }
        setMyApplicationsState((current) => ({ ...current, error: "", loading: true }));
        try {
            const data = await listMyFinanceApplications(myApplicationQuery);
            setMyApplicationsState({ data, error: "", loading: false });
        } catch (err) {
            setMyApplicationsState((current) => ({
                ...current,
                error: err.message || "加载我的申请列表失败",
                loading: false,
            }));
        }
    }, [myApplicationQuery, session?.canCreateApplication]);

    // 充值详情的 App 目录来自 recharge-apps（含 Yumi/Aslan 等 legacy 外部账单源）；接口未就绪时回退到财务通用 App 列表。
    const rechargeApps = useMemo(
        () =>
            rechargeAppsState.loaded && rechargeAppsState.items.length
                ? rechargeAppsState.items
                : optionsState.data.apps,
        [optionsState.data.apps, rechargeAppsState],
    );

    const loadRechargeApps = useCallback(async () => {
        if (!canViewFinance) {
            return;
        }
        try {
            const items = await fetchFinanceRechargeApps();
            setRechargeAppsState({ items, loaded: true });
        } catch {
            setRechargeAppsState({ items: [], loaded: false });
        }
    }, [canViewFinance]);

    const loadRechargeDetails = useCallback(async () => {
        if (!canViewFinance) {
            return;
        }
        setRechargeDetailsState((current) => ({ ...current, error: "", loading: true }));
        try {
            const data = await listFinanceRechargeDetails(rechargeDetailQuery, rechargeApps);
            setRechargeDetailsState({ data, error: "", loading: false });
        } catch (err) {
            setRechargeDetailsState((current) => ({
                ...current,
                error: err.message || "加载充值流水失败",
                loading: false,
            }));
        }
    }, [canViewFinance, rechargeApps, rechargeDetailQuery]);

    const loadRechargeSummary = useCallback(async () => {
        if (!canViewFinance) {
            return;
        }
        setRechargeSummaryState((current) => ({ ...current, loading: true }));
        try {
            const { merged, perApp } = await fetchFinanceRechargeSummaries(rechargeBaseQuery, rechargeApps);
            // 环比：把当前时间范围整体前移一个周期再查一次；未选时间范围时不算环比。
            let prev = null;
            const { endMs, startMs } = rechargeDetailFilters.timeRange;
            if (startMs && endMs && endMs > startMs) {
                const length = endMs - startMs;
                const prevQuery = { ...rechargeBaseQuery, end_at_ms: startMs, start_at_ms: startMs - length };
                prev = (await fetchFinanceRechargeSummaries(prevQuery, rechargeApps)).merged;
            }
            setRechargeSummaryState({ merged, loading: false, perApp, prev });
        } catch {
            setRechargeSummaryState((current) => ({ ...current, loading: false }));
        }
    }, [canViewFinance, rechargeApps, rechargeBaseQuery, rechargeDetailFilters.timeRange]);

    const loadRechargeOverview = useCallback(async () => {
        if (!canViewFinance) {
            return;
        }
        setRechargeOverviewState((current) => ({ ...current, loading: true }));
        try {
            const data = await fetchFinanceRechargeOverview(rechargeBaseQuery, rechargeApps);
            setRechargeOverviewState({ data, loading: false });
        } catch {
            setRechargeOverviewState((current) => ({ ...current, loading: false }));
        }
    }, [canViewFinance, rechargeApps, rechargeBaseQuery]);

    const loadRecon = useCallback(async () => {
        if (!canViewFinance || activeView !== "recon") {
            return;
        }
        const month = reconMonthMeta(reconMonthOffset);
        const query = {
            ...rechargeBaseQuery,
            end_at_ms: month.endMs,
            keyword: "",
            recharge_type: "",
            start_at_ms: month.startMs,
        };
        setReconState((current) => ({ ...current, loading: true }));
        try {
            const [{ merged }, overview] = await Promise.all([
                fetchFinanceRechargeSummaries(query, rechargeApps),
                fetchFinanceRechargeOverview(query, rechargeApps),
            ]);
            setReconState({ loading: false, overview, summary: merged });
        } catch {
            setReconState((current) => ({ ...current, loading: false }));
        }
    }, [activeView, canViewFinance, rechargeApps, rechargeBaseQuery, reconMonthOffset]);

    const rechargeAppCode = rechargeDetailFilters.appCode;
    // 一次拉齐所有 App 的区域目录：区域筛选下拉用当前 App 的，流水区域列在“全部 App”下要跨 App 显示名称。
    const loadRechargeRegions = useCallback(async () => {
        if (!canViewFinance || !rechargeApps.length) {
            return;
        }
        setRechargeRegionsState((current) => ({ ...current, loading: true }));
        try {
            const entries = await Promise.all(
                rechargeApps.map(async (app) => {
                    try {
                        return [app.appCode, await listFinanceRechargeRegions(app.appCode)];
                    } catch {
                        return [app.appCode, []];
                    }
                }),
            );
            setRechargeRegionsState({ byApp: Object.fromEntries(entries), loading: false });
        } catch {
            setRechargeRegionsState((current) => ({ ...current, loading: false }));
        }
    }, [canViewFinance, rechargeApps]);

    const refreshGooglePaid = useCallback(
        async (transactionIds) => {
            if (!rechargeAppCode || !transactionIds?.length || googlePaidRefreshing) {
                return;
            }
            setGooglePaidRefreshing(true);
            try {
                const results = await refreshFinanceGoogleRechargePaid(rechargeAppCode, transactionIds);
                const failed = results.filter((item) => item.error).length;
                const succeeded = results.length - failed;
                showToast(
                    failed
                        ? `谷歌实付同步完成：成功 ${succeeded} 笔，失败 ${failed} 笔`
                        : `谷歌实付同步完成：${succeeded} 笔`,
                    failed ? "warning" : "success",
                );
                await Promise.all([loadRechargeDetails(), loadRechargeOverview()]);
            } catch (err) {
                showToast(err.message || "查询谷歌实付失败", "error");
            } finally {
                setGooglePaidRefreshing(false);
            }
        },
        [googlePaidRefreshing, loadRechargeDetails, loadRechargeOverview, rechargeAppCode, showToast],
    );

    const exportRechargeBills = useCallback(async () => {
        if (!rechargeAppCode || rechargeExporting) {
            return;
        }
        setRechargeExporting(true);
        try {
            const timestamp = new Date()
                .toLocaleString("sv-SE", { timeZone: "Asia/Shanghai" })
                .replaceAll(/[: ]/g, "-");
            await downloadCsv(
                () => exportFinanceRechargeBills(rechargeAppCode, rechargeDetailQuery),
                `充值明细-${rechargeAppCode}-${timestamp}.csv`,
            );
            showToast("充值明细已导出", "success");
        } catch (err) {
            showToast(err.message || "导出充值明细失败", "error");
        } finally {
            setRechargeExporting(false);
        }
    }, [rechargeAppCode, rechargeDetailQuery, rechargeExporting, showToast]);

    const loadApplications = useCallback(async () => {
        if (!session?.canAuditApplication) {
            return;
        }
        setApplicationsState((current) => ({ ...current, error: "", loading: true }));
        try {
            const data = await listFinanceApplications(applicationQuery);
            setApplicationsState({ data, error: "", loading: false });
        } catch (err) {
            setApplicationsState((current) => ({
                ...current,
                error: err.message || "加载申请列表失败",
                loading: false,
            }));
        }
    }, [applicationQuery, session?.canAuditApplication]);

    const loadWithdrawals = useCallback(async () => {
        if (!session?.canViewWithdrawalApplications) {
            return;
        }
        setWithdrawalsState((current) => ({ ...current, error: "", loading: true }));
        try {
            const data = await listFinanceWithdrawalApplications(withdrawalQuery);
            setWithdrawalsState({ data, error: "", loading: false });
        } catch (err) {
            setWithdrawalsState((current) => ({
                ...current,
                error: err.message || "加载提现申请列表失败",
                loading: false,
            }));
        }
    }, [session?.canViewWithdrawalApplications, withdrawalQuery]);

    const loadCoinSellerRechargeOrders = useCallback(async () => {
        if (!session?.canViewCoinSellerRechargeOrders) {
            return;
        }
        setCoinSellerRechargeOrdersState((current) => ({ ...current, error: "", loading: true }));
        try {
            const data = await listFinanceCoinSellerRechargeOrders(coinSellerRechargeOrderQuery);
            setCoinSellerRechargeOrdersState({ data, error: "", loading: false });
        } catch (err) {
            setCoinSellerRechargeOrdersState((current) => ({
                ...current,
                error: err.message || "加载币商充值订单失败",
                loading: false,
            }));
        }
    }, [coinSellerRechargeOrderQuery, session?.canViewCoinSellerRechargeOrders]);

    useEffect(() => {
        loadOptions();
    }, [loadOptions]);

    useEffect(() => {
        loadMyApplications();
    }, [loadMyApplications]);

    useEffect(() => {
        loadRechargeApps();
    }, [loadRechargeApps]);

    useEffect(() => {
        loadRechargeDetails();
    }, [loadRechargeDetails]);

    useEffect(() => {
        loadRechargeSummary();
    }, [loadRechargeSummary]);

    useEffect(() => {
        loadRechargeOverview();
    }, [loadRechargeOverview]);

    useEffect(() => {
        loadRecon();
    }, [loadRecon]);

    useEffect(() => {
        loadRechargeRegions();
    }, [loadRechargeRegions]);

    useEffect(() => {
        loadApplications();
    }, [loadApplications]);

    useEffect(() => {
        loadWithdrawals();
    }, [loadWithdrawals]);

    useEffect(() => {
        loadCoinSellerRechargeOrders();
    }, [loadCoinSellerRechargeOrders]);

    const operationOptions = useMemo(
        () => filterOperationsByPermissions(optionsState.data.operations, session?.permissions || []),
        [optionsState.data.operations, session?.permissions],
    );

    const submitApplication = async (event) => {
        event.preventDefault();
        if (!session?.canCreateApplication) {
            showToast("无发起财务申请权限", "error");
            return;
        }

        const payload = buildApplicationPayload(form);
        const validationMessage = validateApplicationPayload(payload);
        if (validationMessage) {
            showToast(validationMessage, "warning");
            return;
        }

        setSubmitting(true);
        try {
            const result = await createFinanceApplication(cleanPayload(payload));
            setForm({ ...DEFAULT_APPLICATION_FORM, appCode: payload.appCode });
            setCreateDialogOpen(false);
            showToast(
                result?.dingTalkNotified === false ? "申请已提交，钉钉通知未确认" : "申请已提交并通知财务",
                "success",
            );
            await loadMyApplications();
            if (session.canAuditApplication) {
                await loadApplications();
            }
        } catch (err) {
            showToast(err.message || "发起申请失败", "error");
        } finally {
            setSubmitting(false);
        }
    };

    const submitAudit = async ({ decision, remark }) => {
        if (!auditTarget?.id || !session?.canAuditApplication) {
            return;
        }
        setAuditLoading(true);
        try {
            const submitter = decision === "approved" ? approveFinanceApplication : rejectFinanceApplication;
            await submitter(auditTarget.id, { auditRemark: remark });
            showToast(decision === "approved" ? "申请已通过" : "申请已拒绝", "success");
            setAuditTarget(null);
            await loadApplications();
        } catch (err) {
            showToast(err.message || "审核失败", "error");
        } finally {
            setAuditLoading(false);
        }
    };

    const submitWithdrawalAudit = async ({ auditImageUrl, decision, remark }) => {
        if (!withdrawalAuditTarget?.id || !session?.canAuditWithdrawalApplications) {
            return;
        }
        setWithdrawalAuditLoading(true);
        try {
            const submitter =
                decision === "approved" ? approveFinanceWithdrawalApplication : rejectFinanceWithdrawalApplication;
            await submitter(withdrawalAuditTarget.id, cleanPayload({ auditImageUrl, auditRemark: remark }));
            showToast(decision === "approved" ? "提现申请已通过" : "提现申请已拒绝", "success");
            setWithdrawalAuditTarget(null);
            await loadWithdrawals();
        } catch (err) {
            showToast(err.message || "审核提现申请失败", "error");
        } finally {
            setWithdrawalAuditLoading(false);
        }
    };

    const submitCoinSellerRechargeOrder = async (payload) => {
        if (!session?.canCreateCoinSellerRechargeOrder) {
            showToast("无创建币商充值订单权限", "error");
            return null;
        }
        setCoinSellerRechargeOrderActionLoading("create");
        try {
            const order = await createFinanceCoinSellerRechargeOrder(cleanPayload(payload));
            showToast("币商充值订单已创建", "success");
            await loadCoinSellerRechargeOrders();
            return order;
        } catch (err) {
            showToast(err.message || "创建币商充值订单失败", "error");
            return null;
        } finally {
            setCoinSellerRechargeOrderActionLoading("");
        }
    };

    const verifyCoinSellerRechargeReceipt = async (payload) => {
        if (!session?.canVerifyCoinSellerRechargeOrder) {
            showToast("无校验币商充值订单权限", "error");
            return null;
        }
        try {
            const verification = await verifyFinanceCoinSellerRechargeReceipt(cleanPayload(payload));
            showToast(verification?.verified ? "订单号校验通过" : verification?.failureReason || "订单号校验未通过", verification?.verified ? "success" : "error");
            return verification;
        } catch (err) {
            showToast(err.message || "校验订单号失败", "error");
            return null;
        }
    };

    const verifyCoinSellerRechargeOrder = async (order) => {
        if (!order?.id || !session?.canVerifyCoinSellerRechargeOrder) {
            return;
        }
        setCoinSellerRechargeOrderActionLoading(`verify:${order.id}`);
        try {
            await verifyFinanceCoinSellerRechargeOrder(order.id);
            showToast("订单校验已完成", "success");
            await loadCoinSellerRechargeOrders();
        } catch (err) {
            showToast(err.message || "校验币商充值订单失败", "error");
        } finally {
            setCoinSellerRechargeOrderActionLoading("");
        }
    };

    const grantCoinSellerRechargeOrder = async (order) => {
        if (!order?.id || !session?.canGrantCoinSellerRechargeOrder) {
            return;
        }
        setCoinSellerRechargeOrderActionLoading(`grant:${order.id}`);
        try {
            await grantFinanceCoinSellerRechargeOrder(order.id);
            showToast("币商充值已发放", "success");
            await loadCoinSellerRechargeOrders();
        } catch (err) {
            showToast(err.message || "发放币商充值失败", "error");
        } finally {
            setCoinSellerRechargeOrderActionLoading("");
        }
    };

    const updateFilters = (nextFilters) => {
        setFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 }));
    };

    const updateRechargeDetailFilters = (nextFilters) => {
        setRechargeDetailFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 }));
    };

    const updateMyFilters = (nextFilters) => {
        setMyFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 }));
    };

    const updateWithdrawalFilters = (nextFilters) => {
        setWithdrawalFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 }));
    };

    const updateCoinSellerRechargeOrderFilters = (nextFilters) => {
        setCoinSellerRechargeOrderFilters((current) => ({ ...current, ...nextFilters, page: nextFilters.page || 1 }));
    };

    const closeCreateDialog = (_, reason) => {
        if (submitting || reason === "backdropClick") {
            return;
        }
        setCreateDialogOpen(false);
    };

    if (sessionState.loading) {
        return <StateScreen title="正在进入财务系统" />;
    }

    if (sessionState.error) {
        return <StateScreen actionHref="/login" actionText="重新登录" title={sessionState.error} />;
    }

    if (!session?.canAccessFinance) {
        return <StateScreen title="无财务系统权限" />;
    }

    const presets = timePresets();
    const activePreset = presets.find(
        (preset) =>
            String(preset.range.startMs || "") === String(rechargeDetailFilters.timeRange.startMs || "") &&
            String(preset.range.endMs || "") === String(rechargeDetailFilters.timeRange.endMs || ""),
    );
    const isFinanceView = FINANCE_VIEWS.has(activeView);
    const financeToolbar =
        isFinanceView && session.canViewAppRechargeDetails ? (
            <>
                <div className="finance-seg" role="group" aria-label="时间范围">
                    {presets.map((preset) => (
                        <button
                            className={activePreset?.key === preset.key ? "is-on" : ""}
                            key={preset.key}
                            type="button"
                            onClick={() => updateRechargeDetailFilters({ timeRange: preset.range })}
                        >
                            {preset.label}
                        </button>
                    ))}
                </div>
                <TimeRangeFilter
                    label="自定义 · 中国时区"
                    value={rechargeDetailFilters.timeRange}
                    onChange={(timeRange) => updateRechargeDetailFilters({ timeRange })}
                />
                <div className="finance-seg" role="group" aria-label="计价单位">
                    {[
                        ["usd", "USD"],
                        ["coin", "金币"],
                    ].map(([value, label]) => (
                        <button
                            className={rechargeDetailFilters.currency === value ? "is-on" : ""}
                            key={value}
                            type="button"
                            onClick={() =>
                                updateRechargeDetailFilters({ currency: value, page: rechargeDetailFilters.page })
                            }
                        >
                            {label}
                        </button>
                    ))}
                </div>
            </>
        ) : null;

    const appBar =
        isFinanceView && session.canViewAppRechargeDetails ? (
            <div className="finance-appbar">
                <button
                    className={["finance-appchip", rechargeDetailFilters.appCode === "" ? "is-on" : ""]
                        .filter(Boolean)
                        .join(" ")}
                    type="button"
                    onClick={() => updateRechargeDetailFilters({ appCode: "", regionId: "" })}
                >
                    全部 App
                </button>
                {rechargeApps.map((app) => (
                    <button
                        className={["finance-appchip", rechargeDetailFilters.appCode === app.appCode ? "is-on" : ""]
                            .filter(Boolean)
                            .join(" ")}
                        key={app.appCode}
                        type="button"
                        onClick={() => updateRechargeDetailFilters({ appCode: app.appCode, regionId: "" })}
                    >
                        {app.appName || app.appCode}
                    </button>
                ))}
            </div>
        ) : null;

    return (
        <FinanceShell
            activeView={activeView}
            appBar={appBar}
            canAudit={session.canAuditApplication}
            canCreate={session.canCreateApplication}
            canViewCoinSellerRechargeOrders={session.canViewCoinSellerRechargeOrders}
            canViewRechargeDetails={session.canViewAppRechargeDetails}
            canViewWithdrawals={session.canViewWithdrawalApplications}
            loading={
                optionsState.loading ||
                rechargeDetailsState.loading ||
                myApplicationsState.loading ||
                applicationsState.loading ||
                withdrawalsState.loading ||
                coinSellerRechargeOrdersState.loading
            }
            session={session}
            toolbar={financeToolbar}
            onViewChange={setActiveView}
        >
            {activeView === "overview" && session.canViewAppRechargeDetails ? (
                <FinanceOverview
                    apps={rechargeApps}
                    currency={rechargeDetailFilters.currency}
                    filters={rechargeDetailFilters}
                    loading={rechargeSummaryState.loading || rechargeOverviewState.loading}
                    overview={rechargeOverviewState.data}
                    perAppSummaries={rechargeSummaryState.perApp}
                    prevSummary={rechargeSummaryState.prev}
                    regions={rechargeOverviewState.data.regions}
                    summary={rechargeSummaryState.merged}
                    onFiltersChange={updateRechargeDetailFilters}
                    onGoUnsynced={() => {
                        updateRechargeDetailFilters({ paidState: "unsynced", rechargeType: "" });
                        setActiveView("rechargeDetails");
                    }}
                    onOpenApp={(appCode) => {
                        updateRechargeDetailFilters({ appCode, regionId: "" });
                        setActiveView("rechargeDetails");
                    }}
                    onOpenWithdrawals={() => setActiveView("withdrawals")}
                />
            ) : activeView === "coinSellerRechargeOrders" && session.canViewCoinSellerRechargeOrders ? (
                <FinanceCoinSellerRechargeOrderList
                    actionLoading={coinSellerRechargeOrderActionLoading}
                    apps={rechargeApps}
                    canCreate={session.canCreateCoinSellerRechargeOrder}
                    canGrant={session.canGrantCoinSellerRechargeOrder}
                    canVerify={session.canVerifyCoinSellerRechargeOrder}
                    error={coinSellerRechargeOrdersState.error}
                    filters={coinSellerRechargeOrderFilters}
                    loading={coinSellerRechargeOrdersState.loading}
                    orders={coinSellerRechargeOrdersState.data}
                    onCreate={submitCoinSellerRechargeOrder}
                    onFiltersChange={updateCoinSellerRechargeOrderFilters}
                    onGrant={grantCoinSellerRechargeOrder}
                    onReload={loadCoinSellerRechargeOrders}
                    onVerify={verifyCoinSellerRechargeOrder}
                    onVerifyReceipt={verifyCoinSellerRechargeReceipt}
                />
            ) : activeView === "recon" && session.canViewAppRechargeDetails ? (
                <FinanceReconciliation
                    loading={reconState.loading}
                    month={reconMonthMeta(reconMonthOffset)}
                    overview={reconState.overview}
                    summary={reconState.summary}
                    onMonthChange={(delta) => setReconMonthOffset((current) => Math.min(0, current + delta))}
                />
            ) : activeView === "rechargeDetails" && session.canViewAppRechargeDetails ? (
                <FinanceRechargeDetailList
                    apps={rechargeApps}
                    bills={rechargeDetailsState.data}
                    currency={rechargeDetailFilters.currency}
                    error={rechargeDetailsState.error}
                    exporting={rechargeExporting}
                    filters={rechargeDetailFilters}
                    googlePaidRefreshing={googlePaidRefreshing}
                    loading={rechargeDetailsState.loading}
                    regions={rechargeRegionsState.byApp[rechargeAppCode] || []}
                    regionsByApp={rechargeRegionsState.byApp}
                    summary={rechargeSummaryState.merged}
                    onExport={exportRechargeBills}
                    onFiltersChange={updateRechargeDetailFilters}
                    onRefreshGooglePaid={refreshGooglePaid}
                    onReload={() => {
                        loadRechargeDetails();
                        loadRechargeSummary();
                        loadRechargeOverview();
                    }}
                />
            ) : activeView === "applications" && session.canAuditApplication ? (
                <FinanceApplicationList
                    applications={applicationsState.data}
                    error={applicationsState.error}
                    filters={filters}
                    loading={applicationsState.loading}
                    operations={optionsState.data.operations}
                    options={optionsState.data}
                    onAudit={setAuditTarget}
                    onFiltersChange={updateFilters}
                    onReload={loadApplications}
                />
            ) : activeView === "withdrawals" && session.canViewWithdrawalApplications ? (
                <FinanceWithdrawalApplicationList
                    applications={withdrawalsState.data}
                    canAudit={session.canAuditWithdrawalApplications}
                    error={withdrawalsState.error}
                    filters={withdrawalFilters}
                    loading={withdrawalsState.loading}
                    options={optionsState.data}
                    onAudit={setWithdrawalAuditTarget}
                    onFiltersChange={updateWithdrawalFilters}
                    onReload={loadWithdrawals}
                />
            ) : (
                <FinanceMyApplicationList
                    applications={myApplicationsState.data}
                    error={myApplicationsState.error}
                    filters={myFilters}
                    loading={myApplicationsState.loading}
                    operations={optionsState.data.operations}
                    options={optionsState.data}
                    onCreate={() => setCreateDialogOpen(true)}
                    onFiltersChange={updateMyFilters}
                    onReload={loadMyApplications}
                />
            )}
            <Dialog
                fullWidth
                maxWidth="md"
                open={createDialogOpen}
                slotProps={{ paper: { className: "finance-create-dialog-paper" } }}
                onClose={closeCreateDialog}
            >
                <DialogTitle>发起申请</DialogTitle>
                <DialogContent className="finance-create-dialog">
                    <FinanceApplicationForm
                        apps={optionsState.data.apps}
                        disabled={!session.canCreateApplication}
                        error={optionsState.error}
                        form={form}
                        loading={optionsState.loading || submitting}
                        operations={operationOptions}
                        walletIdentities={optionsState.data.walletIdentities}
                        onCancel={closeCreateDialog}
                        onChange={setForm}
                        onSubmit={submitApplication}
                    />
                </DialogContent>
            </Dialog>
            <FinanceAuditDialog
                application={auditTarget}
                loading={auditLoading}
                operations={optionsState.data.operations}
                open={Boolean(auditTarget)}
                onClose={() => setAuditTarget(null)}
                onSubmit={submitAudit}
            />
            <FinanceAuditDialog
                application={withdrawalAuditTarget}
                loading={withdrawalAuditLoading}
                operations={optionsState.data.operations}
                open={Boolean(withdrawalAuditTarget)}
                requireApprovalImage
                requireRejectRemark
                onClose={() => setWithdrawalAuditTarget(null)}
                onSubmit={submitWithdrawalAudit}
            />
        </FinanceShell>
    );
}

function StateScreen({ actionHref = "", actionText = "", title }) {
    return (
        <main className="finance-state-screen">
            <section className="finance-state-panel">
                <h1>{title}</h1>
                {actionHref ? <a href={actionHref}>{actionText}</a> : null}
            </section>
        </main>
    );
}

function cleanPayload(payload) {
    return Object.fromEntries(Object.entries(payload).filter(([, value]) => value !== ""));
}
