import ContentCopyOutlined from "@mui/icons-material/ContentCopyOutlined";
import OpenInNewOutlined from "@mui/icons-material/OpenInNewOutlined";
import UndoOutlined from "@mui/icons-material/UndoOutlined";
import Tab from "@mui/material/Tab";
import Tabs from "@mui/material/Tabs";
import { useEffect, useState } from "react";
import { Link, useLocation } from "react-router-dom";
import { AdminPrettyDisplayID, AdminUserIdentity } from "@/shared/ui/AdminUserIdentity.jsx";
import { Button } from "@/shared/ui/Button.jsx";
import { useConfirm } from "@/shared/ui/ConfirmProvider.jsx";
import { useToast } from "@/shared/ui/ToastProvider.jsx";
import { formatMillis } from "@/shared/utils/time.js";
import { issueAppUserAccessToken, revokeAppUserResource } from "@/features/app-users/api";
import { appUserStatusLabels } from "@/features/app-users/constants.js";
import {
    BanCountdown,
    GenderAgeTag,
    GenderValue,
    LevelValue,
    OperatorValue,
    RolesValue,
    formatUsdMinor,
} from "@/features/app-users/components/AppUserValues.jsx";
import styles from "@/features/app-users/app-users.module.css";

const detailTabs = [
    ["overview", "总览"],
    ["assets", "资产"],
    ["resources", "资源"],
    ["status", "状态记录"],
    ["device", "设备"],
];

export function AppUserDetailView({
    fullDetailsHref = "",
    loading = false,
    mode = "drawer",
    onOpenFullDetails,
    onReloadUser,
    user,
}) {
    const location = useLocation();
    const [activeTab, setActiveTab] = useState("overview");
    const balances = user.balances || [];
    const equippedResources = user.equippedResources || [];
    const resources = user.resources || [];

    useEffect(() => {
        // 抽屉复用同一个组件切换用户时回到总览，避免新用户沿用上一位用户的深层 Tab 而遗漏核心信息。
        setActiveTab("overview");
    }, [user.userId]);

    return (
        <div className={[styles.detailView, mode === "page" ? styles.detailViewPage : ""].filter(Boolean).join(" ")}>
            <div className={styles.detailStickyHeader}>
                <div className={styles.detailHero}>
                    <AdminUserIdentity
                        namePrefix={<GenderAgeTag age={user.age} gender={user.gender} />}
                        size="large"
                        user={user}
                    />
                    <div className={styles.detailHeroActions}>
                        <AppUserStatus status={user.status} />
                        {fullDetailsHref ? (
                            <Button
                                component={Link}
                                state={{ from: `${location.pathname}${location.search}${location.hash}` }}
                                to={fullDetailsHref}
                                type={undefined}
                                onClick={onOpenFullDetails}
                            >
                                <OpenInNewOutlined fontSize="small" />
                                完整详情
                            </Button>
                        ) : null}
                    </div>
                </div>
                <div className={styles.detailMetrics}>
                    <SummaryMetric label="财富" value={formatSummaryLevel(user.levels?.wealth)} />
                    <SummaryMetric label="魅力" value={formatSummaryLevel(user.levels?.charm)} />
                    <SummaryMetric label="游戏" value={formatSummaryLevel(user.levels?.game)} />
                    <SummaryMetric label="VIP" value={formatVipSummary(user.vip)} />
                    <SummaryMetric label="金币" value={formatNumber(user.coin)} />
                    <SummaryMetric label="钻石" value={formatNumber(user.diamond)} />
                    <SummaryMetric label="累计充值" value={formatCompactUsdMinor(user.cumulativeRechargeUsdMinor)} />
                </div>
                {loading ? <div className={styles.detailLoading}>正在刷新用户详情...</div> : null}
                <Tabs
                    aria-label="用户详情分类"
                    className={styles.detailTabs}
                    value={activeTab}
                    variant="scrollable"
                    onChange={(_, value) => setActiveTab(value)}
                >
                    {detailTabs.map(([value, label]) => (
                        <Tab
                            className={styles.detailTab}
                            key={value}
                            label={value === "resources" ? `${label} (${equippedResources.length + resources.length})` : label}
                            value={value}
                        />
                    ))}
                </Tabs>
            </div>

            <div className={styles.detailTabPanel} role="tabpanel">
                {activeTab === "overview" ? <OverviewPanel user={user} /> : null}
                {activeTab === "assets" ? <AssetsPanel balances={balances} user={user} /> : null}
                {activeTab === "resources" ? (
                    <ResourcesPanel
                        equippedResources={equippedResources}
                        onReloadUser={onReloadUser}
                        resources={resources}
                        user={user}
                    />
                ) : null}
                {activeTab === "status" ? <StatusPanel user={user} /> : null}
                {activeTab === "device" ? <DevicePanel user={user} /> : null}
            </div>
        </div>
    );
}

function OverviewPanel({ user }) {
    return (
        <>
            <DetailSection title="身份信息">
                <div className={styles.detailGrid}>
                    <DetailItem label="用户 ID" value={<CopyableValue label="复制用户 ID" value={user.userId} />} />
                    <DetailItem
                        label="短 ID"
                        value={
                            <CopyableValue
                                label="复制短 ID"
                                value={user.defaultDisplayUserId || user.displayUserId || user.userId}
                            />
                        }
                    />
                    <DetailItem label="靓号" value={<PrettyValue user={user} />} />
                    <DetailItem label="靓号记录 ID" value={user.prettyId} />
                    <DetailItem label="昵称" value={user.username} />
                    <DetailItem label="性别" value={<GenderValue gender={user.gender} />} />
                    <DetailItem label="生日" value={user.birth} />
                    <DetailItem label="年龄" value={formatAge(user.age)} />
                    <DetailItem label="注册设备" value={user.registerDevice} />
                    <DetailItem label="身份" value={<RolesValue roles={user.roles} />} />
                </div>
            </DetailSection>
            <DetailSection title="等级与会员">
                <div className={styles.detailGrid}>
                    <DetailItem label="财富等级" value={<LevelValue level={user.levels?.wealth} showReal />} />
                    <DetailItem label="魅力等级" value={<LevelValue level={user.levels?.charm} showReal />} />
                    <DetailItem label="游戏等级" value={<LevelValue level={user.levels?.game} showReal />} />
                    <DetailItem label="VIP 等级" value={<VipDetailValue vip={user.vip} />} />
                    <DetailItem label="VIP 到期" value={formatVipExpire(user.vip)} />
                </div>
            </DetailSection>
        </>
    );
}

function AssetsPanel({ balances, user }) {
    return (
        <>
            <DetailSection title="资产概览">
                <div className={styles.detailGrid}>
                    <DetailItem label="金币" value={formatNumber(user.coin)} />
                    <DetailItem label="钻石" value={formatNumber(user.diamond)} />
                    <DetailItem label="累计充值" value={formatUsdMinor(user.cumulativeRechargeUsdMinor)} />
                </div>
            </DetailSection>
            <DetailSection title={`资产余额 (${balances.length})`}>
                <AssetBalanceList balances={balances} />
            </DetailSection>
        </>
    );
}

function ResourcesPanel({ equippedResources, onReloadUser, resources, user }) {
    const confirm = useConfirm();
    const { showToast } = useToast();
    const [revokingEntitlementId, setRevokingEntitlementId] = useState("");

    const revokeResource = async (resource) => {
        const entitlementId = String(resource?.entitlementId || "").trim();
        if (!entitlementId || revokingEntitlementId) {
            return;
        }
        const resourceName = resourceDisplayName(resource);
        const accepted = await confirm({
            title: "撤回用户素材",
            message: `撤回后，用户「${user.username || user.displayUserId || user.userId}」将立即失去素材「${resourceName}」；若正在佩戴会同时卸下。同一资源组的其他素材不受影响。`,
            confirmText: "确认撤回",
            tone: "danger",
        });
        if (!accepted) {
            return;
        }

        setRevokingEntitlementId(entitlementId);
        try {
            // entitlement 是用户素材实例的唯一标识；按它撤回才能避免 sourceGrantId 对应资源组时误伤同组素材。
            await revokeAppUserResource(user.userId, entitlementId, {
                reason: `后台用户详情撤回素材：${resourceName}`.slice(0, 256),
            });
        } catch (error) {
            showToast(error.message || "素材撤回失败", "error");
            setRevokingEntitlementId("");
            return;
        }

        showToast(`素材「${resourceName}」已撤回`, "success");
        try {
            // 撤回成功后重新读取 owner 服务事实，不能只在前端本地删行掩盖后端未生效或残留佩戴状态。
            await onReloadUser?.();
        } catch (error) {
            showToast(error.message || "素材已撤回，但用户详情刷新失败", "warning");
        } finally {
            setRevokingEntitlementId("");
        }
    };

    return (
        <>
            <DetailSection title={`当前佩戴 (${equippedResources.length})`}>
                <ResourceList
                    resources={equippedResources}
                    revokingEntitlementId={revokingEntitlementId}
                    onRevokeResource={revokeResource}
                />
            </DetailSection>
            <DetailSection title={`资源资产 (${resources.length})`}>
                <ResourceList
                    resources={resources}
                    revokingEntitlementId={revokingEntitlementId}
                    onRevokeResource={revokeResource}
                />
            </DetailSection>
        </>
    );
}

function StatusPanel({ user }) {
    return (
        <DetailSection title="账号状态与记录">
            <div className={styles.detailGrid}>
                <DetailItem label="状态" value={appUserStatusLabels[user.status] || user.status || "-"} />
                <DetailItem label="封禁剩余" value={<BanCountdown ban={user.ban} status={user.status} />} />
                <DetailItem label="封禁原因" value={user.ban?.reason} wide />
                <DetailItem label="国家" value={formatCountry(user)} />
                <DetailItem label="区域" value={user.regionName || (user.regionId ? `区域 ${user.regionId}` : "-")} />
                <DetailItem label="最新登录" value={formatMillis(user.lastLoginAtMs)} />
                <DetailItem label="最近活跃" value={formatMillis(user.lastActiveAtMs)} />
                <DetailItem label="最新登录 IP" value={<LatestLoginIpValue user={user} />} wide />
                <DetailItem label="当前 App 版本" value={formatAppVersion(user.appVersion, user.buildNumber)} />
                <DetailItem label="OpenID" value={<OpenIdListValue identities={user.thirdPartyIdentities} />} wide />
                <DetailItem label="当前 Token" value={<AccessTokenValue userId={user.userId} />} wide />
                <DetailItem
                    label="最新操作"
                    value={<OperatorValue operatedAtMs={user.lastOperatedAtMs} operator={user.lastOperator} />}
                    wide
                />
                <DetailItem label="创建时间" value={formatMillis(user.createdAtMs)} />
                <DetailItem label="更新时间" value={formatMillis(user.updatedAtMs)} />
            </div>
        </DetailSection>
    );
}

function DevicePanel({ user }) {
    const devices = user.devices || [];
    return (
        <>
            <DetailSection title={`当前设备 (${devices.length})`}>
                {devices.length ? (
                    devices.map((device) => (
                        <div className={styles.detailGrid} key={device.deviceId}>
                            <DetailItem
                                label="设备型号"
                                value={[device.manufacturer, device.deviceModel].filter(Boolean).join(" ")}
                            />
                            {/* iOS 设备也会上报，所以统一叫“系统版本”而不是“安卓版本”。 */}
                            <DetailItem label="系统版本" value={device.osVersion} />
                            <DetailItem label="IMEI" value={device.imei} />
                            <DetailItem
                                label="设备 ID"
                                value={<CopyableValue label="复制设备 ID" value={device.deviceId} />}
                            />
                            <DetailItem
                                label="App 版本"
                                value={formatAppVersion(device.appVersion, device.buildNumber)}
                            />
                            <DetailItem label="最近活跃" value={formatMillis(device.lastSeenAtMs)} />
                            <DetailItem label="首次记录" value={formatMillis(device.firstSeenAtMs)} />
                        </div>
                    ))
                ) : (
                    <div className={styles.emptyInline}>暂无设备上报数据（需要 App ≥ 携带设备信息的版本）</div>
                )}
            </DetailSection>
            <DetailSection title="注册设备">
                <div className={styles.detailGrid}>
                    <DetailItem label="注册设备" value={user.registerDevice} />
                    <DetailItem label="注册系统版本" value={user.registerOsVersion} />
                    <DetailItem
                        label="注册设备 ID"
                        value={<CopyableValue label="复制注册设备 ID" value={user.registerDeviceId} />}
                    />
                </div>
            </DetailSection>
        </>
    );
}

function DetailSection({ children, title }) {
    return (
        <section className={styles.detailSection}>
            <h3 className={styles.detailSectionTitle}>{title}</h3>
            {children}
        </section>
    );
}

function DetailItem({ label, value, wide = false }) {
    const isElement = value && typeof value === "object";
    return (
        <div className={[styles.detailItem, wide ? styles.detailItemWide : ""].filter(Boolean).join(" ")}>
            <span className={styles.detailLabel}>{label}</span>
            <span className={styles.detailValue}>
                {isElement ? value : value === undefined || value === null || value === "" ? "-" : value}
            </span>
        </div>
    );
}

function SummaryMetric({ label, value }) {
    return (
        <div className={styles.detailMetric}>
            <span>{label}</span>
            <strong>{value}</strong>
        </div>
    );
}

function CopyableValue({ display, label, value }) {
    const [copied, setCopied] = useState(false);
    const normalized = String(value ?? "").trim();

    if (!normalized) {
        return "-";
    }

    const copy = async () => {
        // display 只影响展示（如超长 Token 截断），复制必须始终写入完整原值，否则复制出的凭证不可用。
        await copyText(normalized);
        setCopied(true);
        window.setTimeout(() => setCopied(false), 1200);
    };

    return (
        <span className={styles.copyableDetailValue}>
            <span>{display || normalized}</span>
            <button aria-label={label} className={styles.copyDetailButton} title={copied ? "已复制" : label} type="button" onClick={copy}>
                <ContentCopyOutlined fontSize="inherit" />
            </button>
        </span>
    );
}

function LatestLoginIpValue({ user }) {
    if (!user.lastLoginIp) {
        return "-";
    }
    // 国家码与记录时间放在 IP 后做纯文本补充，复制按钮只复制 IP 本身，方便直接贴进风控查询。
    const suffix = [
        user.lastLoginIpCountryCode,
        user.lastLoginIpAtMs ? `记录于 ${formatMillis(user.lastLoginIpAtMs)}` : "",
    ]
        .filter(Boolean)
        .join(" · ");
    return (
        <span className={styles.copyableDetailValue}>
            <CopyableValue label="复制登录 IP" value={user.lastLoginIp} />
            {suffix ? <span>{suffix}</span> : null}
        </span>
    );
}

function OpenIdListValue({ identities }) {
    const list = identities || [];
    if (!list.length) {
        return "-";
    }
    // 一个用户可能绑定多个三方账号（每个 provider 一条），逐行展示避免混淆不同渠道的 openid。
    return (
        <span>
            {list.map((identity) => (
                <span className={styles.copyableDetailValue} key={`${identity.provider}-${identity.openid}`}>
                    <span>{identity.provider || "-"}</span>
                    <span>·</span>
                    <CopyableValue label="复制 OpenID" value={identity.openid} />
                </span>
            ))}
        </span>
    );
}

function AccessTokenValue({ userId }) {
    const [error, setError] = useState("");
    const [loading, setLoading] = useState(false);
    const [token, setToken] = useState(null);

    useEffect(() => {
        // 抽屉复用组件切换用户时清空上一位用户的 Token，避免把他人凭证误复制到当前用户的排查里。
        setError("");
        setLoading(false);
        setToken(null);
    }, [userId]);

    const fetchToken = async () => {
        setError("");
        setLoading(true);
        try {
            setToken(await issueAppUserAccessToken(userId));
        } catch (issueError) {
            // 服务端会返回“该用户当前没有活跃会话”等具体原因，直接透出比通用兜底文案更利于排查。
            setToken(null);
            setError(issueError instanceof Error && issueError.message ? issueError.message : "获取 Token 失败");
        } finally {
            setLoading(false);
        }
    };

    if (token) {
        return (
            <span className={styles.copyableDetailValue}>
                <CopyableValue
                    display={truncateToken(token.accessToken)}
                    label="复制完整 Token"
                    value={token.accessToken}
                />
                {token.expiresInSec > 0 ? <span>有效期 {token.expiresInSec} 秒</span> : null}
            </span>
        );
    }

    return (
        <span className={styles.copyableDetailValue}>
            {/* Token 签发在服务端会写入操作日志且属于敏感凭证，因此不随 Tab 打开自动获取，只保留显式按钮。
                详情视图没有权限上下文（useAuth 依赖 AuthProvider，抽屉/详情页测试均不包裹），
                所以不在前端隐藏按钮：无 app-user:token 权限时后端返回 403，错误文案原样透出。 */}
            <Button disabled={loading} onClick={fetchToken}>
                {loading ? "获取中..." : "获取 Token"}
            </Button>
            {error ? <span>{error}</span> : null}
        </span>
    );
}

function truncateToken(value) {
    const normalized = String(value || "");
    // JWT 通常远超一行宽度，仅保留首尾便于肉眼比对；完整值通过复制按钮获取。
    return normalized.length > 28 ? `${normalized.slice(0, 14)}…${normalized.slice(-10)}` : normalized;
}

function PrettyValue({ user }) {
    if (!user.prettyId || !user.prettyDisplayUserId) {
        return "-";
    }
    return <AdminPrettyDisplayID prettyDisplayUserId={user.prettyDisplayUserId} prettyId={user.prettyId} />;
}

function VipDetailValue({ vip }) {
    const level = Number(vip?.level || 0);
    if (level <= 0 || !vip?.active) {
        return "VIP 0";
    }
    return vip.name ? `VIP ${level} · ${vip.name}` : `VIP ${level}`;
}

function AssetBalanceList({ balances }) {
    if (!balances.length) {
        return <div className={styles.emptyInline}>当前无数据</div>;
    }
    return (
        <div className={styles.assetList}>
            {balances.map((balance) => (
                <div className={styles.assetRow} key={balance.assetType}>
                    <div>
                        <div className={styles.assetName}>{formatAssetType(balance.assetType)}</div>
                        <div className={styles.assetMeta}>
                            冻结 {formatAssetAmount(balance.assetType, balance.frozenAmount)}
                        </div>
                    </div>
                    <div className={styles.assetAmount}>
                        {formatAssetAmount(balance.assetType, balance.availableAmount)}
                    </div>
                </div>
            ))}
        </div>
    );
}

function ResourceList({ onRevokeResource, resources, revokingEntitlementId }) {
    if (!resources.length) {
        return <div className={styles.emptyInline}>当前无数据</div>;
    }
    return (
        <ul className={styles.resourceList}>
            {resources.map((resource) => (
                <li className={styles.resourceItem} key={resource.entitlementId || resource.resourceId}>
                    <ResourceThumb resource={resource} />
                    <div className={styles.resourceBody}>
                        <div className={styles.resourceTitle}>
                            <span>{resourceDisplayName(resource)}</span>
                            {resource.equipped ? <span className={styles.resourceTag}>佩戴中</span> : null}
                        </div>
                        <div className={styles.resourceMeta}>
                            {formatResourceType(resource.resourceType)} · 剩余 {formatNumber(resource.remainingQuantity)} / {formatNumber(resource.quantity)}
                        </div>
                        <div className={styles.resourceMeta}>到期 {formatExpireTime(resource.expiresAtMs)}</div>
                    </div>
                    {resource.entitlementId ? (
                        <Button
                            aria-label={`撤回素材 ${resourceDisplayName(resource)}`}
                            className={styles.resourceRevokeButton}
                            disabled={Boolean(revokingEntitlementId)}
                            variant="danger"
                            onClick={() => onRevokeResource(resource)}
                        >
                            <UndoOutlined fontSize="small" />
                            {revokingEntitlementId === resource.entitlementId ? "撤回中..." : "撤回"}
                        </Button>
                    ) : null}
                </li>
            ))}
        </ul>
    );
}

function resourceDisplayName(resource) {
    return resource?.name || resource?.resourceCode || `资源 ${resource?.resourceId || "-"}`;
}

function ResourceThumb({ resource }) {
    const imageUrl = resource.previewUrl || resource.assetUrl || resource.animationUrl;
    if (!imageUrl) {
        return <span className={styles.resourceThumbFallback}>{resource.name?.slice(0, 1) || "资"}</span>;
    }
    return <img alt="" className={styles.resourceThumb} src={imageUrl} />;
}

function AppUserStatus({ status }) {
    const tone = status === "active" ? "running" : "danger";
    return (
        <span className={`status-badge status-badge--${tone}`}>
            <span className="status-point" />
            {appUserStatusLabels[status] || status || "-"}
        </span>
    );
}

function formatSummaryLevel(level) {
    const value = Number(level?.displayLevel ?? level?.realLevel);
    return Number.isFinite(value) && value >= 0 ? `Lv${Math.trunc(value)}` : "-";
}

function formatVipSummary(vip) {
    const level = Number(vip?.level || 0);
    return level > 0 && vip?.active ? `VIP ${level}` : "VIP 0";
}

function formatCompactUsdMinor(value) {
    const amount = Number(value) / 100;
    if (!Number.isFinite(amount)) {
        return "-";
    }
    return new Intl.NumberFormat("en-US", {
        currency: "USD",
        maximumFractionDigits: Math.abs(amount) >= 1000 ? 1 : 2,
        notation: Math.abs(amount) >= 1000 ? "compact" : "standard",
        style: "currency",
    }).format(amount);
}

function formatAppVersion(appVersion, buildNumber) {
    if (!appVersion) {
        return "-";
    }
    return buildNumber ? `${appVersion} (build ${buildNumber})` : appVersion;
}

function formatCountry(user) {
    return user.countryDisplayName || user.countryName || user.country || "-";
}

function formatNumber(value) {
    const number = Number(value || 0);
    return Number.isFinite(number) ? number.toLocaleString() : "-";
}

function formatAge(value) {
    if (value === undefined || value === null || value === "") {
        return "-";
    }
    const age = Number(value);
    return Number.isFinite(age) && age >= 0 ? `${Math.trunc(age)} 岁` : "-";
}

function formatVipExpire(vip) {
    if (Number(vip?.level || 0) <= 0) {
        return "-";
    }
    return formatExpireTime(vip?.expiresAtMs);
}

function formatAssetType(value) {
    const normalized = String(value || "").toUpperCase();
    const labels = { COIN: "金币", DIAMOND: "钻石" };
    return labels[normalized] || normalized || "-";
}

function formatAssetAmount(assetType, value) {
    const normalizedAssetType = String(assetType || "").toUpperCase();
    if (normalizedAssetType.endsWith("_USD")) {
        const amountMinor = Number(value);
        if (!Number.isFinite(amountMinor)) {
            return "-";
        }
        // 工资类 USD 资产由钱包按美分存储；只在展示层换算为美元，避免把 100 美分误显示为 100 美元。
        return new Intl.NumberFormat("en-US", {
            currency: "USD",
            currencyDisplay: "narrowSymbol",
            style: "currency",
        }).format(amountMinor / 100);
    }
    return formatNumber(value);
}

function formatResourceType(value) {
    const labels = {
        avatar_frame: "头像框",
        badge: "徽章",
        chat_bubble: "聊天气泡",
        emoji_pack: "表情包",
        floating_screen: "飘屏",
        gift: "礼物",
        mic_seat_animation: "麦位动画",
        mic_seat_icon: "麦位图标",
        profile_card: "资料卡",
        vehicle: "座驾",
    };
    return labels[value] || value || "-";
}

function formatExpireTime(value) {
    const expiresAtMs = Number(value || 0);
    if (!Number.isFinite(expiresAtMs) || expiresAtMs <= 0) {
        return "永久";
    }
    return formatMillis(expiresAtMs);
}

async function copyText(value) {
    if (navigator.clipboard?.writeText) {
        try {
            await navigator.clipboard.writeText(value);
            return;
        } catch {
            // 后台可能运行在非安全上下文，Clipboard API 被拒绝时继续使用兼容复制路径。
        }
    }
    const textarea = document.createElement("textarea");
    textarea.value = value;
    textarea.style.position = "fixed";
    textarea.style.opacity = "0";
    document.body.appendChild(textarea);
    textarea.select();
    document.execCommand("copy");
    textarea.remove();
}
