import Dialog from "@mui/material/Dialog";
import DialogActions from "@mui/material/DialogActions";
import DialogContent from "@mui/material/DialogContent";
import DialogTitle from "@mui/material/DialogTitle";
import MenuItem from "@mui/material/MenuItem";
import TextField from "@mui/material/TextField";
import { useState } from "react";
import { Button } from "@/shared/ui/Button.jsx";
import { TimeText } from "@/shared/ui/TimeText.jsx";
import { luckyGiftPoolKey } from "../api.js";
import {
    EXPERIMENT_ARM_LABELS,
    EXPERIMENT_ARMS,
    experimentArmStat,
    experimentStatusBadge,
    formatTrafficPercent,
    isActiveExperiment,
    trafficPercentError,
} from "../experimentForm.js";
import { formatNumber, formatPercent } from "../format.js";
import { LuckyGiftPoolActions } from "./LuckyGiftPoolActions.jsx";
import { OpsStatusBadge } from "./OpsStatusBadge.jsx";

// AB 实验管理弹窗：展示两组统计并承载放量、暂停/恢复、白名单、结束实验四类操作。
// 所有请求都由 OpsCenterApp 的回调执行（失败 toast 保留弹窗），这里只负责输入校验与二次确认。
export function LuckyGiftExperimentManageDialog({
    busy,
    canCreditPool,
    canDebitPool,
    canManage,
    experiment,
    onAdjustTraffic,
    onClose,
    onCreditPool,
    onDebitPool,
    onEnd,
    onRemoveOverride,
    onSetStatus,
    onUpsertOverride,
    poolBalances = [],
    poolBusy = false,
    statsLoading,
}) {
    const [trafficInput, setTrafficInput] = useState(() => String(experiment.treatment_traffic_percent ?? ""));
    const [trafficError, setTrafficError] = useState("");
    const [overrideUserKey, setOverrideUserKey] = useState("");
    const [overrideArm, setOverrideArm] = useState("treatment");
    const [overrideError, setOverrideError] = useState("");
    const [endConfirmArm, setEndConfirmArm] = useState("");

    const paused = experiment.status === "paused";
    const completed = experiment.status === "completed";
    // completed 只读：历史入口打开时仅展示分组数据与获胜结果，不再提供任何写操作。
    const editable = canManage && isActiveExperiment(experiment);
    const badge = experimentStatusBadge(experiment);
    const overrides = Array.isArray(experiment.overrides) ? experiment.overrides : [];
    const armStrategies = EXPERIMENT_ARMS.map((arm) => experimentArmStat(experiment, arm)?.strategy_version).filter(
        Boolean,
    );
    // 水位以 app+pool+strategy 为账本主键，而不是实验 arm。跨策略实验两组各自命中一口水位；
    // 同策略实验则必须展示共享语义，避免运营从两张卡各补一次而误以为资金彼此隔离。
    const sharedStrategyPool = armStrategies.length === EXPERIMENT_ARMS.length && new Set(armStrategies).size === 1;

    const submitTraffic = (event) => {
        event.preventDefault();
        const error = trafficPercentError(trafficInput);
        setTrafficError(error);
        if (error) {
            return;
        }
        onAdjustTraffic(Number(trafficInput));
    };

    const submitOverride = (event) => {
        event.preventDefault();
        const userKey = overrideUserKey.trim();
        if (!userKey) {
            setOverrideError("请输入用户 ID");
            return;
        }
        setOverrideError("");
        setOverrideUserKey("");
        onUpsertOverride({ arm: overrideArm, userKey });
    };

    return (
        <Dialog
            aria-labelledby="ops-experiment-manage-title"
            fullWidth
            maxWidth="md"
            open
            scroll="paper"
            onClose={busy ? undefined : onClose}
        >
            <DialogTitle className="ops-experiment-title" id="ops-experiment-manage-title">
                <span>{completed ? "实验详情" : "实验管理"}</span>
                <small>{experiment.name || experiment.experiment_id}</small>
            </DialogTitle>
            <DialogContent className="ops-experiment-content" dividers>
                <div className="ops-experiment-metrics">
                    <ExperimentMetric label="应用" value={experiment.app_code} />
                    <ExperimentMetric label="奖池" value={experiment.pool_id} />
                    <ExperimentMetric
                        label="状态"
                        value={badge ? <OpsStatusBadge label={badge.label} tone={badge.tone} /> : "-"}
                    />
                    <ExperimentMetric label="开始时间" value={<TimeText value={experiment.started_at_ms} />} />
                    <ExperimentMetric
                        label="实验组流量"
                        value={formatTrafficPercent(experiment.treatment_traffic_percent)}
                    />
                    <ExperimentMetric label="白名单" value={`${overrides.length} 人`} />
                </div>

                {paused ? (
                    <div className="ops-pool-adjustment-note" role="status">
                        实验已暂停：全部流量（含白名单）临时回到对照组，恢复后回到原分组。
                    </div>
                ) : null}
                {completed ? (
                    <div className="ops-pool-adjustment-note" role="status">
                        实验已结束：{EXPERIMENT_ARM_LABELS[experiment.winner_arm] || "获胜方"}获胜，配置已重新发布为 v
                        {experiment.final_rule_version || experiment.winner_rule_version || "-"} 并全量生效。
                    </div>
                ) : null}

                <div className="ops-experiment-arms">
                    {EXPERIMENT_ARMS.map((arm) => (
                        <ExperimentArmCard
                            arm={arm}
                            busy={busy}
                            canCreditPool={canCreditPool}
                            canDebitPool={canDebitPool}
                            canEnd={editable}
                            experiment={experiment}
                            key={arm}
                            poolBalances={poolBalances}
                            poolBusy={poolBusy}
                            statsLoading={statsLoading}
                            onCreditPool={onCreditPool}
                            onDebitPool={onDebitPool}
                            onPickWinner={setEndConfirmArm}
                        />
                    ))}
                </div>
                {sharedStrategyPool && (canCreditPool || canDebitPool) ? (
                    <div className="ops-pool-adjustment-note" role="status">
                        两组使用同一策略，共用这口奖池水位；从任一组入口调整都会同步生效。
                    </div>
                ) : null}

                {/* editable 才渲染确认层：结束成功后 status 变为 completed，确认层随之收起。 */}
                {editable && endConfirmArm ? (
                    <div className="ops-experiment-confirm" role="alert">
                        <strong>确认以{EXPERIMENT_ARM_LABELS[endConfirmArm]}结束实验？</strong>
                        <p>
                            {EXPERIMENT_ARM_LABELS[endConfirmArm]}（v
                            {endConfirmArm === "control"
                                ? experiment.control_rule_version
                                : experiment.treatment_rule_version}
                            ）的配置将重新发布为新的最新版本并对全量用户生效；实验立即结束且不可恢复，之后配置页恢复常规发布。
                        </p>
                        <div>
                            <Button disabled={busy} onClick={() => setEndConfirmArm("")}>
                                取消
                            </Button>
                            <Button disabled={busy} variant="danger" onClick={() => onEnd(endConfirmArm)}>
                                确认结束并发布
                            </Button>
                        </div>
                    </div>
                ) : null}

                {editable ? (
                    <section aria-label="实验控制" className="ops-experiment-section">
                        <h3>放量与状态</h3>
                        <div className="ops-experiment-controls">
                            <form className="ops-experiment-inline-form" onSubmit={submitTraffic}>
                                <TextField
                                    disabled={busy}
                                    error={Boolean(trafficError)}
                                    helperText={
                                        trafficError ||
                                        "0 表示仅白名单进入实验组；放量单调，调大不会把已在实验组的用户踢回"
                                    }
                                    label="实验组流量 (%)"
                                    size="small"
                                    slotProps={{ htmlInput: { inputMode: "decimal", max: 100, min: 0, step: "0.01" } }}
                                    type="number"
                                    value={trafficInput}
                                    onChange={(event) => {
                                        setTrafficInput(event.target.value);
                                        setTrafficError("");
                                    }}
                                />
                                <Button disabled={busy} type="submit">
                                    应用
                                </Button>
                            </form>
                            <div className="ops-experiment-inline-form">
                                <Button
                                    disabled={busy}
                                    variant={paused ? "success" : undefined}
                                    onClick={() => onSetStatus(paused ? "running" : "paused")}
                                >
                                    {paused ? "恢复实验" : "暂停实验"}
                                </Button>
                                <span className="ops-field-note">
                                    {paused
                                        ? "恢复后所有用户回到暂停前的分组。"
                                        : "暂停后全部流量（含白名单）回到对照组。"}
                                </span>
                            </div>
                        </div>
                    </section>
                ) : null}

                <section aria-label="白名单用户" className="ops-experiment-section ops-experiment-overrides">
                    <h3>白名单用户</h3>
                    <p className="ops-field-note">
                        白名单用户不参与哈希分流，固定进入指定分组；流量为 0 时只有白名单进入实验组。
                    </p>
                    {overrides.length ? (
                        <ul>
                            {overrides.map((override) => (
                                <li key={override.user_key}>
                                    <code>{override.user_key}</code>
                                    <span>{EXPERIMENT_ARM_LABELS[override.arm] || override.arm}</span>
                                    {editable ? (
                                        <Button
                                            aria-label={`移除白名单 ${override.user_key}`}
                                            disabled={busy}
                                            size="small"
                                            variant="danger"
                                            onClick={() => onRemoveOverride(override.user_key)}
                                        >
                                            移除
                                        </Button>
                                    ) : null}
                                </li>
                            ))}
                        </ul>
                    ) : (
                        <p className="ops-field-note">暂无白名单用户</p>
                    )}
                    {editable ? (
                        <form className="ops-experiment-inline-form" onSubmit={submitOverride}>
                            <TextField
                                disabled={busy}
                                error={Boolean(overrideError)}
                                helperText={overrideError}
                                label="用户 ID"
                                size="small"
                                value={overrideUserKey}
                                onChange={(event) => {
                                    setOverrideUserKey(event.target.value);
                                    setOverrideError("");
                                }}
                            />
                            <TextField
                                disabled={busy}
                                label="分组"
                                select
                                size="small"
                                value={overrideArm}
                                onChange={(event) => setOverrideArm(event.target.value)}
                            >
                                {EXPERIMENT_ARMS.map((arm) => (
                                    <MenuItem key={arm} value={arm}>
                                        {EXPERIMENT_ARM_LABELS[arm]}
                                    </MenuItem>
                                ))}
                            </TextField>
                            <Button disabled={busy} type="submit">
                                添加
                            </Button>
                        </form>
                    ) : null}
                </section>
            </DialogContent>
            <DialogActions>
                <Button disabled={busy} onClick={onClose}>
                    关闭
                </Button>
            </DialogActions>
        </Dialog>
    );
}

function ExperimentArmCard({
    arm,
    busy,
    canCreditPool,
    canDebitPool,
    canEnd,
    experiment,
    onCreditPool,
    onDebitPool,
    onPickWinner,
    poolBalances,
    poolBusy,
    statsLoading,
}) {
    const stat = experimentArmStat(experiment, arm);
    const ruleVersion = arm === "control" ? experiment.control_rule_version : experiment.treatment_rule_version;
    const isWinner = experiment.status === "completed" && experiment.winner_arm === arm;
    const strategyVersion = stat?.strategy_version || "";
    const poolIdentity = {
        app_code: experiment.app_code,
        pool_id: experiment.pool_id,
        strategy_version: strategyVersion,
    };
    const pool = strategyVersion
        ? (poolBalances || []).find((item) => luckyGiftPoolKey(item) === luckyGiftPoolKey(poolIdentity))
        : null;
    // 保留完整策略身份作为禁用按钮的 aria/tooltip 上下文；若水位接口暂未返回该账本，
    // LuckyGiftPoolActions 会禁止提交，不能用 0 余额伪装成已加载的可调整奖池。
    const poolActionTarget = pool || poolIdentity;
    // 统计尚未返回时明确展示“加载中”，避免运营把未加载误读成 0（0 消费也是有效实验结论）。
    const statValue = (value, format) => (stat ? format(value) : statsLoading ? "加载中" : "-");
    const poolValue = (value) => (pool ? formatNumber(value) : statsLoading ? "加载中" : "-");

    return (
        <section
            aria-label={EXPERIMENT_ARM_LABELS[arm]}
            className={["ops-experiment-arm", isWinner ? "ops-experiment-arm--winner" : ""].filter(Boolean).join(" ")}
        >
            <header className="ops-experiment-arm__head">
                <strong>{EXPERIMENT_ARM_LABELS[arm]}</strong>
                <span>{ruleVersion ? `v${ruleVersion}` : "-"}</span>
                {isWinner ? <OpsStatusBadge label="获胜" tone="succeeded" /> : null}
            </header>
            <dl className="ops-experiment-stats">
                <div>
                    <dt>策略</dt>
                    <dd>{stat?.strategy_version || "-"}</dd>
                </div>
                <div>
                    <dt>抽奖次数</dt>
                    <dd>{statValue(stat?.total_draws, formatNumber)}</dd>
                </div>
                <div>
                    <dt>参与用户</dt>
                    <dd>{statValue(stat?.unique_users, formatNumber)}</dd>
                </div>
                <div>
                    <dt>消费金币</dt>
                    <dd>{statValue(stat?.total_spent_coins, formatNumber)}</dd>
                </div>
                <div>
                    <dt>返奖金币</dt>
                    <dd>{statValue(stat?.total_reward_coins, formatNumber)}</dd>
                </div>
                <div>
                    <dt>实际 RTP</dt>
                    <dd>{statValue(stat?.actual_rtp_percent, formatPercent)}</dd>
                </div>
                <div>
                    <dt>奖池余额</dt>
                    <dd>{poolValue(pool?.balance)}</dd>
                </div>
                <div>
                    <dt>可用水位</dt>
                    <dd>{poolValue(pool?.available_balance)}</dd>
                </div>
            </dl>
            {strategyVersion ? (
                <LuckyGiftPoolActions
                    canCredit={canCreditPool}
                    canDebit={canDebitPool}
                    disabled={poolBusy}
                    pool={poolActionTarget}
                    onCredit={onCreditPool}
                    onDebit={onDebitPool}
                />
            ) : null}
            {canEnd ? (
                <Button
                    aria-label={`选择${EXPERIMENT_ARM_LABELS[arm]}为最终版本`}
                    disabled={busy}
                    size="small"
                    onClick={() => onPickWinner(arm)}
                >
                    选择此组为最终版本
                </Button>
            ) : null}
        </section>
    );
}

function ExperimentMetric({ label, value }) {
    return (
        <div className="ops-config-metric">
            <span>{label}</span>
            <strong>{value || "-"}</strong>
        </div>
    );
}
