<script setup lang="ts">
import { ref, onMounted, computed } from 'vue';
import { useRouter } from 'vue-router';
import { ElMessage, ElMessageBox } from 'element-plus';
import { useAdminLocale } from '../composables/useAdminLocale';
import { resolveFormError, resolveApiError } from '../i18n/form-validation';
import api from '../api';
import { clearStaffSession } from '../stores/auth';

const { t, localeTag } = useAdminLocale();
const router = useRouter();

import {
  emptyPlayerCreateForm,
  emptyPlayerEditForm,
  editFormFromDetail,
  buildCreatePlayerPayload,
  type PlayerRow,
  type PlayerDetail,
  type PlayerCreateForm,
  type PlayerEditForm,
  formatPlayerAffiliationLabel,
  assertPlayerUsername,
} from './user-form';
import {
  emptyAgentEditForm,
  editFormFromAgentDetail,
  type AgentRow,
  type AgentDetail,
  type AgentEditForm,
} from './agent-form';
import { subAgentAccountStatus } from './agent/agent-sub-agent-form';

type DisplayAgentRow = AgentRow;
import {
  formatAmount,
  formatAmountFull,
  shouldCompactAmount as shouldCompact,
} from '../utils/format-amount';
import {
  shouldToggleExpandOnRowClick,
  expandableTableRowClassName,
} from '../utils/expandable-table';
import AdminTableEmpty from '../components/AdminTableEmpty.vue';
import WalletTransferContext from '../components/WalletTransferContext.vue';
import AgentCreditContext from '../components/AgentCreditContext.vue';
import { useAdminPlayerTransfer } from '../composables/useAdminPlayerTransfer';
import {
  fetchAdminAgentCreditContext,
  maxCreditIncreaseAmount,
  type AgentCreditAdjustContext,
} from '../utils/agent-credit-context';

/* ─── Tier-1 agent list ─── */
const tier1Agents = ref<AgentRow[]>([]);
const tier1Total = ref(0);
const tier1Page = ref(1);
const tier1PageSize = ref(20);
const tier1Keyword = ref('');
const tier1FilterStatus = ref('');

/* ─── Tier-2 agent list ─── */
const tier2Agents = ref<AgentRow[]>([]);
const tier2Total = ref(0);
const tier2Page = ref(1);
const tier2PageSize = ref(20);
const tier2Keyword = ref('');
const tier2FilterStatus = ref('');

/* ─── View tab: players | tier1Agents | tier2Agents ─── */
const activeViewTab = ref('players');

/* ─── All players list ─── */
const allPlayers = ref<PlayerRow[]>([]);
const playerTotal = ref(0);
const playerPage = ref(1);
const playerPageSize = ref(20);
const playerKeyword = ref('');
const playerFilterStatus = ref('');
const playerFilterAgent = ref('');
const playerLoading = ref(false);
const agentOptions = ref<{ id: string; username: string; level: number; parentUsername?: string | null }[]>([]);

/* ─── Expansion state ─── */
const expandedSet = ref(new Set<string>());
const agentPlayersMap = ref<Record<string, PlayerRow[]>>({});
const expandLoading = ref<Record<string, boolean>>({});
const tier1AgentTableRef = ref();
const tier2AgentTableRef = ref();

/* ─── Dialogs ─── */
const createVisible = ref(false);
const editPlayerVisible = ref(false);
const editAgentVisible = ref(false);
const detailPlayerVisible = ref(false);
const detailAgentVisible = ref(false);
const creditVisible = ref(false);
const createLoading = ref(false);
const editPlayerLoading = ref(false);
const editAgentLoading = ref(false);
const creditLoading = ref(false);

/* ─── Create form (unified) ─── */
const createForm = ref<PlayerCreateForm>(emptyPlayerCreateForm());
const createParentAgentId = ref('');
const createParentLocked = ref(false);
const createAccountMode = ref(0); // 0=player, 1=tier1Agent, 2=subAgent

/* ─── Edit forms ─── */
const editPlayerForm = ref<PlayerEditForm>(emptyPlayerEditForm());
const editAgentForm = ref<AgentEditForm>(emptyAgentEditForm());
const editingId = ref('');

/* ─── Detail ─── */
const playerDetail = ref<PlayerDetail | null>(null);
const agentDetail = ref<AgentDetail | null>(null);

/* ─── Credit ─── */
const creditForm = ref({ amount: 10000, remark: '' });
const creditContext = ref<AgentCreditAdjustContext | null>(null);
const creditContextLoading = ref(false);

/* ─── Global settings ─── */
const playerSettings = ref({ allowPasswordChange: true, allowUsernameChange: false });
const bettingLimits = ref({
  minStake: 1,
  maxStakeSingle: 50000,
  maxStakeParlay: 20000,
  maxPayoutSingle: 500000,
  maxPayoutParlay: 1000000,
  dailyStakeLimit: 200000,
});
const settingsSaving = ref(false);
const limitsSaving = ref(false);
const agentSuspendSettings = ref({
  suspendFreezeDirectPlayers: false,
  suspendBlockPlayerLogin: false,
});
const agentSuspendSaving = ref(false);
const resetAllowed = ref(false);
const resetLoading = ref(false);
const resetConfirmPhrase = ref('');
const settingsCollapseOpen = ref<string[]>([]);

const createDialogTitle = computed(() => {
  if (createAccountMode.value === 1) return t('agent.dialog.create');
  if (createAccountMode.value === 2) return t('agent_portal.create_sub_agent_dialog');
  return t('user.dialog.create');
});

const tier1AgentOptions = computed(() => agentOptions.value.filter((a) => a.level === 1));

function agentOptionLabel(a: { username: string; id: string; level: number; parentUsername?: string | null }) {
  if (a.level === 2 && a.parentUsername) {
    return `${a.parentUsername} / ${a.username} (#${a.id})`;
  }
  return `${a.username} (#${a.id})`;
}

function resolveCreateParentLabel(agentId: string) {
  const hit = agentOptions.value.find((a) => a.id === agentId);
  if (hit) return agentOptionLabel(hit);
  const tier1 = tier1Agents.value.find((a) => a.userId === agentId);
  if (tier1) return tier1.username;
  const tier2 = tier2Agents.value.find((a) => a.userId === agentId);
  if (tier2) {
    return tier2.parentUsername ? `${tier2.parentUsername} / ${tier2.username}` : tier2.username;
  }
  return agentId;
}

/* ─── Init ─── */
onMounted(() => {
  loadPlayerSettings();
  loadBettingLimits();
  loadAgentSuspendSettings();
  loadResetDatabaseStatus();
  loadAgentOptions();
  loadAllPlayers();
  loadTier1Agents();
  loadTier2Agents();
});

/* ─── Load tier-1 agents ─── */
async function loadTier1Agents() {
  const { data } = await api.get('/admin/agents', {
    params: {
      page: tier1Page.value,
      pageSize: tier1PageSize.value,
      keyword: tier1Keyword.value.trim() || undefined,
      status: tier1FilterStatus.value || undefined,
      level: 1,
    },
  });
  tier1Agents.value = data.data.items as AgentRow[];
  tier1Total.value = data.data.total;
}

function onTier1PageChange(p: number) {
  tier1Page.value = p;
  loadTier1Agents();
}

function onTier1SizeChange(size: number) {
  tier1PageSize.value = size;
  tier1Page.value = 1;
  loadTier1Agents();
}

function searchTier1Agents() {
  tier1Page.value = 1;
  loadTier1Agents();
}

/* ─── Load tier-2 agents ─── */
async function loadTier2Agents() {
  const { data } = await api.get('/admin/agents', {
    params: {
      page: tier2Page.value,
      pageSize: tier2PageSize.value,
      keyword: tier2Keyword.value.trim() || undefined,
      status: tier2FilterStatus.value || undefined,
      level: 2,
    },
  });
  tier2Agents.value = data.data.items as AgentRow[];
  tier2Total.value = data.data.total;
}

function onTier2PageChange(p: number) {
  tier2Page.value = p;
  loadTier2Agents();
}

function onTier2SizeChange(size: number) {
  tier2PageSize.value = size;
  tier2Page.value = 1;
  loadTier2Agents();
}

function searchTier2Agents() {
  tier2Page.value = 1;
  loadTier2Agents();
}

function reloadAgentLists() {
  loadTier1Agents();
  loadTier2Agents();
}

/* ─── Load main agent list ─── */
async function load() {
  reloadAgentLists();
}

async function loadAgentOptions() {
  try {
    const { data } = await api.get('/admin/agents/options');
    agentOptions.value = data.data;
  } catch {
    agentOptions.value = [];
  }
}

async function loadAllPlayers() {
  playerLoading.value = true;
  try {
    const params: Record<string, unknown> = {
      page: playerPage.value,
      pageSize: playerPageSize.value,
      keyword: playerKeyword.value.trim() || undefined,
      status: playerFilterStatus.value || undefined,
    };
    if (playerFilterAgent.value) {
      params.parentId = playerFilterAgent.value;
    }
    const { data } = await api.get('/admin/users', { params });
    allPlayers.value = data.data.items as PlayerRow[];
    playerTotal.value = data.data.total;
  } catch {
    allPlayers.value = [];
    playerTotal.value = 0;
  } finally {
    playerLoading.value = false;
  }
}

function searchPlayers() {
  playerPage.value = 1;
  loadAllPlayers();
}

function onPlayerPageChange(p: number) {
  playerPage.value = p;
  loadAllPlayers();
}

function onPlayerSizeChange(size: number) {
  playerPageSize.value = size;
  playerPage.value = 1;
  loadAllPlayers();
}

function affiliationLabel(row: PlayerRow) {
  return formatPlayerAffiliationLabel(row, t('user.type.player'), t('agent.platform_row_name'));
}

function directPlayersTabLabel(ownerName: string, count: number) {
  return `${t('agent.direct_players_title', { name: ownerName })} (${count})`;
}

function onTier1AgentRowClick(row: AgentRow, _column: unknown, event: MouseEvent) {
  onAgentRowClick(row, tier1AgentTableRef, _column, event);
}

function onTier2AgentRowClick(row: AgentRow, _column: unknown, event: MouseEvent) {
  onAgentRowClick(row, tier2AgentTableRef, _column, event);
}

/* ─── Expansion ─── */
async function onExpandChange(row: DisplayAgentRow, expandedRows: DisplayAgentRow[]) {
  expandedSet.value = new Set(expandedRows.map((r) => r.userId));
  if (expandedSet.value.has(row.userId) && !agentPlayersMap.value[row.userId]) {
    await loadExpansionData(row.userId);
  }
}

function onAgentRowClick(row: AgentRow, tableRef: typeof tier1AgentTableRef, _column: unknown, event: MouseEvent) {
  if (!shouldToggleExpandOnRowClick(event)) return;
  tableRef.value?.toggleRowExpansion(row);
}

async function loadExpansionData(agentId: string) {
  expandLoading.value[agentId] = true;
  try {
    const { data } = await api.get('/admin/users', { params: { parentId: agentId, pageSize: 100 } });
    agentPlayersMap.value[agentId] = data.data.items as PlayerRow[];
  } catch {
    agentPlayersMap.value[agentId] = [];
  } finally {
    expandLoading.value[agentId] = false;
  }
}

function getPlayers(agentId: string) {
  return agentPlayersMap.value[agentId] || [];
}

function refreshExpandedAgentPlayers() {
  for (const agentId of expandedSet.value) {
    loadExpansionData(agentId);
  }
}

/* ─── Global settings ─── */
async function loadResetDatabaseStatus() {
  try {
    const { data } = await api.get('/admin/system/reset-database');
    resetAllowed.value = !!data.data?.allowed;
  } catch {
    resetAllowed.value = false;
  }
}

async function resetDatabase() {
  if (resetConfirmPhrase.value !== 'RESET') {
    ElMessage.warning(t('user.reset_database_confirm_label'));
    return;
  }
  try {
    await ElMessageBox.confirm(t('user.reset_database_hint'), t('user.reset_database'), {
      type: 'warning',
      confirmButtonText: t('user.reset_database_btn'),
      cancelButtonText: t('common.cancel'),
    });
  } catch {
    return;
  }
  resetLoading.value = true;
  try {
    const { data } = await api.post('/admin/system/reset-database', { confirmPhrase: 'RESET' });
    const accounts: string[] = data.data?.demoAccounts ?? [];
    ElMessage.success({
      message: `${t('user.reset_database_success')}\n${t('user.reset_database_accounts')}: ${accounts.join(' · ')}`,
      duration: 8000,
    });
    clearStaffSession();
    await router.push('/login');
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  } finally {
    resetLoading.value = false;
  }
}

async function loadBettingLimits() {
  try {
    const { data } = await api.get('/admin/settings/betting-limits');
    bettingLimits.value = data.data;
  } catch {
    /* defaults */
  }
}

async function saveBettingLimits() {
  limitsSaving.value = true;
  try {
    const { data } = await api.put('/admin/settings/betting-limits', bettingLimits.value);
    bettingLimits.value = data.data;
    ElMessage.success(t('msg.saved'));
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
    loadBettingLimits();
  } finally {
    limitsSaving.value = false;
  }
}

async function loadPlayerSettings() {
  try {
    const { data } = await api.get('/admin/users/settings/account');
    playerSettings.value = data.data;
  } catch {
    /* defaults */
  }
}

async function savePlayerSettings() {
  settingsSaving.value = true;
  try {
    const { data } = await api.put('/admin/users/settings/account', playerSettings.value);
    playerSettings.value = data.data;
    ElMessage.success(t('msg.saved'));
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
    loadPlayerSettings();
  } finally {
    settingsSaving.value = false;
  }
}

async function loadAgentSuspendSettings() {
  try {
    const { data } = await api.get('/admin/agents/settings/suspend');
    agentSuspendSettings.value = data.data;
  } catch {
    /* defaults */
  }
}

async function saveAgentSuspendSettings() {
  agentSuspendSaving.value = true;
  try {
    const { data } = await api.put('/admin/agents/settings/suspend', agentSuspendSettings.value);
    agentSuspendSettings.value = data.data;
    ElMessage.success(t('msg.saved'));
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
    loadAgentSuspendSettings();
  } finally {
    agentSuspendSaving.value = false;
  }
}

/* ─── Create (unified) ─── */
function openCreateAccount() {
  createForm.value = emptyPlayerCreateForm();
  createForm.value.asTier1Agent = false;
  createParentAgentId.value = '';
  createParentLocked.value = false;
  createAccountMode.value = 0;
  createVisible.value = true;
}

function openCreateTier1Agent() {
  createForm.value = emptyPlayerCreateForm();
  createForm.value.asTier1Agent = true;
  createParentAgentId.value = '';
  createParentLocked.value = false;
  createAccountMode.value = 1;
  createVisible.value = true;
}

function openCreatePlayer(parentAgentUserId: string) {
  createForm.value = emptyPlayerCreateForm();
  createForm.value.asTier1Agent = false;
  createForm.value.parentId = parentAgentUserId;
  createParentAgentId.value = parentAgentUserId;
  createParentLocked.value = true;
  createAccountMode.value = 0;
  createVisible.value = true;
}

function openCreateSubAgent(parentAgentUserId: string) {
  createForm.value = emptyPlayerCreateForm();
  createForm.value.asTier1Agent = false;
  createParentAgentId.value = parentAgentUserId;
  createParentLocked.value = true;
  createAccountMode.value = 2;
  createVisible.value = true;
}

function openCreateSubAgentFromToolbar() {
  createForm.value = emptyPlayerCreateForm();
  createForm.value.asTier1Agent = false;
  createParentAgentId.value = '';
  createParentLocked.value = false;
  createAccountMode.value = 2;
  createVisible.value = true;
}

async function submitCreate() {
  const isSubAgent = createAccountMode.value === 2;
  const isAgent = createForm.value.asTier1Agent || isSubAgent;
  let payload: Record<string, unknown>;
  try {
    if (isSubAgent) {
      if (!createParentAgentId.value) throw new Error(t('agent.hint.sub_agent_parent'));
      if (!createForm.value.username.trim()) throw new Error(t('err.username_required'));
      if (createForm.value.password.length < 8) throw new Error(t('err.password_min'));
      if (createForm.value.password !== createForm.value.confirmPassword) throw new Error(t('err.password_mismatch'));
      payload = {
        username: createForm.value.username.trim(),
        password: createForm.value.password,
        asSubAgent: true,
        parentAgentId: createParentAgentId.value,
        phone: createForm.value.phone.trim() || undefined,
        email: createForm.value.email.trim() || undefined,
        creditLimit: createForm.value.creditLimit,
        cashbackRate: createForm.value.cashbackRate,
        maxSingleDeposit: createForm.value.maxSingleDeposit > 0 ? createForm.value.maxSingleDeposit : undefined,
        maxDailyDeposit: createForm.value.maxDailyDeposit > 0 ? createForm.value.maxDailyDeposit : undefined,
      };
    } else {
      payload = buildCreatePlayerPayload(createForm.value);
      // When creating player from expansion, ensure parentId is set
      if (createParentAgentId.value && !payload.parentId) {
        payload.parentId = createParentAgentId.value;
      }
    }
  } catch (e) {
    ElMessage.warning(resolveFormError(e, t));
    return;
  }
  createLoading.value = true;
  try {
    await api.post('/admin/users', payload);
    ElMessage.success(
      isAgent
        ? t('msg.agent_created')
        : t('user.msg.created_with_password', { password: createForm.value.password }),
    );
    createVisible.value = false;
    load();
    refreshExpandedParents();
    const parentId = createParentAgentId.value || createForm.value.parentId;
    if (parentId) {
      await loadExpansionData(parentId);
    }
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.create_failed'));
  } finally {
    createLoading.value = false;
  }
}

/* ─── Edit Player ─── */
async function openEditPlayer(id: string) {
  const { data } = await api.get(`/admin/users/${id}`);
  const d = data.data as PlayerDetail;
  editingId.value = id;
  editPlayerForm.value = editFormFromDetail(d);
  editPlayerVisible.value = true;
}

async function submitEditPlayer() {
  if (editPlayerForm.value.newPassword && editPlayerForm.value.newPassword.length < 8) {
    ElMessage.warning(t('err.password_min'));
    return;
  }
  try {
    assertPlayerUsername(editPlayerForm.value.username);
  } catch (e) {
    ElMessage.warning(resolveFormError(e, t));
    return;
  }
  editPlayerLoading.value = true;
  try {
    const newPwd = editPlayerForm.value.newPassword.trim();
    const { data } = await api.put(`/admin/users/${editingId.value}`, {
      username: editPlayerForm.value.username.trim(),
      phone: editPlayerForm.value.phone.trim() || undefined,
      email: editPlayerForm.value.email.trim() || undefined,
      password: newPwd || undefined,
    });
    const updated = data.data as PlayerDetail;
    if (newPwd) {
      editPlayerForm.value.managedPassword = updated.managedPassword ?? newPwd;
      editPlayerForm.value.newPassword = '';
      ElMessage.success(t('user.msg.password_saved', { password: editPlayerForm.value.managedPassword }));
      return;
    }
    ElMessage.success(t('msg.saved'));
    editPlayerVisible.value = false;
    load();
    refreshExpandedParents();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  } finally {
    editPlayerLoading.value = false;
  }
}

/* ─── Edit Agent ─── */
async function openEditAgent(userId: string) {
  const { data } = await api.get(`/admin/agents/${userId}`);
  const d = data.data as AgentDetail;
  editingId.value = userId;
  editAgentForm.value = editFormFromAgentDetail(d);
  editAgentVisible.value = true;
}

async function submitEditAgent() {
  if (editAgentForm.value.newPassword && editAgentForm.value.newPassword.length < 8) {
    ElMessage.warning(t('err.password_min'));
    return;
  }
  editAgentLoading.value = true;
  try {
    const newPwd = editAgentForm.value.newPassword.trim();
    const { data } = await api.put(`/admin/agents/${editingId.value}`, {
      username: editAgentForm.value.username.trim(),
      status: editAgentForm.value.status,
      phone: editAgentForm.value.phone.trim() || undefined,
      email: editAgentForm.value.email.trim() || undefined,
      cashbackRate: editAgentForm.value.cashbackRate,
      maxSingleDeposit: editAgentForm.value.maxSingleDeposit,
      maxDailyDeposit: editAgentForm.value.maxDailyDeposit,
      password: newPwd || undefined,
    });
    const updated = data.data as AgentDetail;
    if (newPwd) {
      editAgentForm.value.managedPassword = updated.managedPassword ?? newPwd;
      editAgentForm.value.newPassword = '';
      ElMessage.success(t('user.msg.password_saved', { password: editAgentForm.value.managedPassword }));
      return;
    }
    ElMessage.success(t('msg.saved'));
    editAgentVisible.value = false;
    load();
    refreshExpandedParents();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.save_failed'));
  } finally {
    editAgentLoading.value = false;
  }
}

/* ─── Detail ─── */
async function openDetailPlayer(id: string) {
  const { data } = await api.get(`/admin/users/${id}`);
  playerDetail.value = data.data as PlayerDetail;
  detailPlayerVisible.value = true;
}

async function openDetailAgent(userId: string) {
  const { data } = await api.get(`/admin/agents/${userId}`);
  agentDetail.value = data.data as AgentDetail;
  detailAgentVisible.value = true;
}

/* ─── Credit ─── */
async function openCredit(userId: string) {
  editingId.value = userId;
  creditForm.value = { amount: 10000, remark: '' };
  creditContext.value = null;
  creditVisible.value = true;
  creditContextLoading.value = true;
  try {
    creditContext.value = await fetchAdminAgentCreditContext(userId);
  } catch (e: unknown) {
    ElMessage.error(resolveApiError(e, t, 'msg.load_failed'));
    creditVisible.value = false;
  } finally {
    creditContextLoading.value = false;
  }
}

async function submitCredit() {
  if (creditForm.value.amount === 0) {
    ElMessage.warning(t('msg.credit_zero'));
    return;
  }
  const maxInc = maxCreditIncreaseAmount(creditContext.value);
  if (creditForm.value.amount > 0 && maxInc !== undefined && creditForm.value.amount > maxInc) {
    ElMessage.warning(t('err.insufficient_credit'));
    return;
  }
  creditLoading.value = true;
  try {
    await api.post(`/admin/agents/${editingId.value}/credit`, {
      amount: creditForm.value.amount,
      requestId: `credit-${editingId.value}-${Date.now()}`,
      remark: creditForm.value.remark || undefined,
    });
    ElMessage.success(t('msg.credit_adjusted'));
    creditVisible.value = false;
    load();
    refreshExpandedParents();
  } catch (e: unknown) {
    ElMessage.error(resolveApiError(e, t, 'msg.credit_adjust_failed'));
  } finally {
    creditLoading.value = false;
  }
}

/* ─── Freeze / Unfreeze ─── */
async function toggleFreezePlayer(row: PlayerRow) {
  const freeze = row.status === 'ACTIVE';
  const action = freeze ? t('common.freeze') : t('common.unfreeze');
  try {
    await ElMessageBox.confirm(
      t('msg.freeze_confirm_body', {
        action,
        name: row.username,
        extra: freeze ? t('msg.freeze_extra') : '',
      }),
      t('msg.freeze_confirm_title', { action }),
      { type: 'warning', confirmButtonText: action, cancelButtonText: t('common.cancel') },
    );
  } catch {
    return;
  }
  try {
    await api.put(`/admin/users/${row.id}`, {
      status: freeze ? 'SUSPENDED' : 'ACTIVE',
    });
    ElMessage.success(t('msg.freeze_done', { action }));
    load();
    refreshExpandedParents();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.freeze_failed', { action }));
  }
}

/* ─── Freeze / Unfreeze Agent ─── */
async function toggleFreezeAgent(row: AgentRow) {
  const accountStatus = subAgentAccountStatus(row);
  const freeze = accountStatus === 'ACTIVE';
  const action = freeze ? t('common.freeze') : t('common.unfreeze');

  if (!freeze) {
    // Unfreeze: simple confirm
    try {
      await ElMessageBox.confirm(
        t('agent.freeze.confirm_unfreeze_body', { name: row.username }),
        t('agent.freeze.confirm_freeze_title'),
        { type: 'info', confirmButtonText: action, cancelButtonText: t('common.cancel') },
      );
    } catch {
      return;
    }
    try {
      await api.put(`/admin/agents/${row.userId}`, { status: 'ACTIVE' });
      ElMessage.success(t('agent.msg.freeze_done', { action }));
      load();
      refreshExpandedParents();
    } catch (e: unknown) {
      const err = e as { response?: { data?: { error?: string } } };
      ElMessage.error(err.response?.data?.error ?? t('msg.freeze_failed', { action }));
    }
    return;
  }

  // Freeze: offer cascade option via a custom dialog
  let freezeDirectPlayers = false;
  try {
    await ElMessageBox.confirm(
      t('agent.freeze.confirm_freeze_body', { name: row.username }),
      t('agent.freeze.confirm_freeze_title'),
      {
        type: 'warning',
        confirmButtonText: action,
        cancelButtonText: t('common.cancel'),
        distinguishCancelAndClose: true,
      },
    );
  } catch {
    return;
  }

  // After confirming freeze, ask about cascade (only when enabled in settings)
  if (row.directPlayerCount > 0 && agentSuspendSettings.value.suspendFreezeDirectPlayers) {
    try {
      await ElMessageBox.confirm(
        t('agent.freeze.cascade_hint'),
        t('agent.freeze.cascade_label'),
        {
          type: 'warning',
          confirmButtonText: t('common.yes') || '是',
          cancelButtonText: t('common.no') || '否',
          distinguishCancelAndClose: true,
        },
      );
      freezeDirectPlayers = true;
    } catch {
      freezeDirectPlayers = false;
    }
  } else if (row.directPlayerCount > 0 && !agentSuspendSettings.value.suspendFreezeDirectPlayers) {
    ElMessage.info(t('agent.suspend.cascade_disabled_hint'));
  }

  try {
    await api.put(`/admin/agents/${row.userId}`, {
      status: 'SUSPENDED',
      freezeDirectPlayers,
    });
    ElMessage.success(
      freezeDirectPlayers
        ? t('agent.msg.cascade_freeze_done')
        : t('agent.msg.freeze_done', { action }),
    );
    load();
    refreshExpandedParents();
  } catch (e: unknown) {
    const err = e as { response?: { data?: { error?: string } } };
    ElMessage.error(err.response?.data?.error ?? t('msg.freeze_failed', { action }));
  }
}

/* ─── Helpers ─── */
function refreshExpandedParents() {
  loadAllPlayers();
  reloadAgentLists();
  refreshExpandedAgentPlayers();
}

const {
  transferVisible,
  transferLoading,
  transferType,
  transferTarget,
  transferAmount,
  transferRemark,
  transferContext,
  transferContextLoading,
  transferAmountRange,
  transferAmountDisabled,
  transferAmountExceedsCap,
  transferAmountCapError,
  transferTitle,
  openTransfer,
  submitTransfer,
} = useAdminPlayerTransfer(async () => {
  load();
  refreshExpandedParents();
});

function creditLine(row: AgentRow) {
  return `${formatAmount(row.creditLimit)} / ${formatAmount(row.usedCredit)} / ${formatAmount(row.availableCredit)}`;
}

function creditLineFull(row: AgentRow) {
  return `${formatAmountFull(row.creditLimit)} / ${formatAmountFull(row.usedCredit)} / ${formatAmountFull(row.availableCredit)}`;
}

function formatTime(v: string) {
  if (!v) return '—';
  return new Date(v).toLocaleString(localeTag.value);
}

function formatLastLogin(v: string | null) {
  if (!v) return t('common.never_login');
  const d = new Date(v);
  const now = new Date();
  const sameDay =
    d.getFullYear() === now.getFullYear() &&
    d.getMonth() === now.getMonth() &&
    d.getDate() === now.getDate();
  if (sameDay) {
    return d.toLocaleTimeString(localeTag.value, { hour: '2-digit', minute: '2-digit' });
  }
  return d.toLocaleString(localeTag.value, {
    month: '2-digit',
    day: '2-digit',
    hour: '2-digit',
    minute: '2-digit',
  });
}

function statusTagType(s: string) {
  return s === 'ACTIVE' ? 'success' : 'warning';
}

function statusLabel(s: string) {
  const key = `user.status.${s}`;
  const v = t(key);
  return v !== key ? v : s;
}

function creditTypeLabel(type: string) {
  if (type === 'CREDIT_INCREASE') return t('agent.credit.increase');
  if (type === 'CREDIT_DECREASE') return t('agent.credit.decrease');
  return type;
}
</script>

<template>
  <div class="admin-list-page agent-mgr-page">
    <!-- ─── Global settings collapse ─── -->
    <el-collapse v-model="settingsCollapseOpen" class="list-settings">
      <el-collapse-item :title="t('user.page_settings')" name="settings">
        <div class="list-settings-block">
          <p class="list-settings-title">{{ t('user.global_settings') }}</p>
          <el-form inline size="small" class="settings-form">
            <el-form-item :label="t('user.field.allow_password_change')">
              <el-switch v-model="playerSettings.allowPasswordChange" :loading="settingsSaving" @change="savePlayerSettings" />
            </el-form-item>
            <el-form-item :label="t('user.field.allow_username_change')">
              <el-switch v-model="playerSettings.allowUsernameChange" :loading="settingsSaving" @change="savePlayerSettings" />
            </el-form-item>
          </el-form>
        </div>
        <div class="list-settings-block">
          <p class="list-settings-title">{{ t('agent.suspend.settings_title') }}</p>
          <p class="list-settings-hint">{{ t('agent.suspend.settings_hint') }}</p>
          <el-form inline size="small" class="settings-form">
            <el-form-item :label="t('agent.suspend.freeze_direct_players')">
              <el-switch
                v-model="agentSuspendSettings.suspendFreezeDirectPlayers"
                :loading="agentSuspendSaving"
                @change="saveAgentSuspendSettings"
              />
            </el-form-item>
            <el-form-item :label="t('agent.suspend.block_player_login')">
              <el-switch
                v-model="agentSuspendSettings.suspendBlockPlayerLogin"
                :loading="agentSuspendSaving"
                @change="saveAgentSuspendSettings"
              />
            </el-form-item>
          </el-form>
        </div>
        <div class="list-settings-block">
          <p class="list-settings-title">{{ t('user.betting_limits') }}</p>
          <el-form inline size="small" class="settings-form limits-form">
            <el-form-item :label="t('user.limit.min_stake')">
              <el-input-number v-model="bettingLimits.minStake" :min="0" :step="1" controls-position="right" />
            </el-form-item>
            <el-form-item :label="t('user.limit.max_stake_single')">
              <el-input-number v-model="bettingLimits.maxStakeSingle" :min="0" :step="100" controls-position="right" />
            </el-form-item>
            <el-form-item :label="t('user.limit.max_stake_parlay')">
              <el-input-number v-model="bettingLimits.maxStakeParlay" :min="0" :step="100" controls-position="right" />
            </el-form-item>
            <el-form-item :label="t('user.limit.max_payout_single')">
              <el-input-number v-model="bettingLimits.maxPayoutSingle" :min="0" :step="1000" controls-position="right" />
            </el-form-item>
            <el-form-item :label="t('user.limit.max_payout_parlay')">
              <el-input-number v-model="bettingLimits.maxPayoutParlay" :min="0" :step="1000" controls-position="right" />
            </el-form-item>
            <el-form-item :label="t('user.limit.daily_stake')">
              <el-input-number v-model="bettingLimits.dailyStakeLimit" :min="0" :step="1000" controls-position="right" />
            </el-form-item>
            <el-form-item>
              <el-button type="primary" :loading="limitsSaving" @click="saveBettingLimits">{{ t('common.save') }}</el-button>
            </el-form-item>
          </el-form>
        </div>
        <div class="list-settings-block list-settings-block--danger">
          <p class="list-settings-title">{{ t('user.reset_database') }}</p>
          <p class="list-settings-hint">{{ t('user.reset_database_hint') }}</p>
          <el-alert v-if="!resetAllowed" type="warning" :closable="false" show-icon class="reset-db-alert" :title="t('user.reset_database_disabled_prod')" />
          <el-form inline size="small" class="settings-form reset-db-form">
            <el-form-item :label="t('user.reset_database_confirm_label')">
              <el-input v-model="resetConfirmPhrase" :placeholder="t('user.reset_database_confirm_ph')" style="width: 160px" :disabled="!resetAllowed" autocomplete="off" />
            </el-form-item>
            <el-form-item>
              <el-button type="danger" plain :loading="resetLoading" :disabled="!resetAllowed || resetConfirmPhrase !== 'RESET'" @click="resetDatabase">{{ t('user.reset_database_btn') }}</el-button>
            </el-form-item>
          </el-form>
        </div>
      </el-collapse-item>
    </el-collapse>

    <el-tabs v-model="activeViewTab" class="mgr-top-tabs">
      <!-- ─── Tab: 全部玩家（默认） ─── -->
      <el-tab-pane :label="`${t('user.type.player')} (${playerTotal})`" name="players">
        <section class="list-panel player-list-panel">
          <div class="list-panel-toolbar">
            <el-form inline class="list-chrome__grow">
              <el-form-item :label="t('common.keyword')">
                <el-input
                  v-model="playerKeyword"
                  :placeholder="t('user.filter.username_ph')"
                  clearable
                  style="width: 180px"
                  @keyup.enter="searchPlayers"
                />
              </el-form-item>
              <el-form-item :label="t('user.filter.agent')">
                <el-select
                  v-model="playerFilterAgent"
                  :placeholder="t('user.filter.agent_ph')"
                  clearable
                  style="width: 200px"
                >
                  <el-option
                    v-for="a in agentOptions"
                    :key="a.id"
                    :label="agentOptionLabel(a)"
                    :value="a.id"
                  />
                </el-select>
              </el-form-item>
              <el-form-item :label="t('common.status')">
                <el-select v-model="playerFilterStatus" :placeholder="t('common.all')" clearable style="width: 120px">
                  <el-option :label="t('user.status.ACTIVE')" value="ACTIVE" />
                  <el-option :label="t('user.status.SUSPENDED')" value="SUSPENDED" />
                </el-select>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="searchPlayers">{{ t('common.search') }}</el-button>
              </el-form-item>
            </el-form>
            <div class="list-chrome__actions">
              <el-button type="primary" @click="openCreateAccount">{{ t('user.create_btn') }}</el-button>
            </div>
          </div>
          <div class="table-wrap">
            <el-table v-loading="playerLoading" :data="allPlayers" stripe>
              <template #empty>
                <AdminTableEmpty />
              </template>
              <el-table-column prop="id" label="ID" width="72" />
              <el-table-column prop="username" :label="t('user.col.username')" min-width="120" />
              <el-table-column :label="t('common.status')" width="88">
                <template #default="{ row }">
                  <el-tag :type="statusTagType(row.status)" size="small">{{ statusLabel(row.status) }}</el-tag>
                </template>
              </el-table-column>
              <el-table-column :label="t('user.col.agent')" min-width="200">
                <template #default="{ row }">
                  <el-tag size="small" type="info" class="affiliation-tag">{{ affiliationLabel(row) }}</el-tag>
                </template>
              </el-table-column>
              <el-table-column :label="t('user.col.balance')" min-width="128" align="right">
                <template #default="{ row }">
                  <el-tooltip :content="`${formatAmountFull(row.availableBalance)} / ${formatAmountFull(row.frozenBalance)}`" placement="top">
                    <span class="amount-compact">{{ formatAmount(row.availableBalance) }} / {{ formatAmount(row.frozenBalance) }}</span>
                  </el-tooltip>
                </template>
              </el-table-column>
              <el-table-column prop="betCount" :label="t('user.col.bets')" width="64" align="center" />
              <el-table-column :label="t('user.col.stake_payout')" min-width="108" align="right">
                <template #default="{ row }">
                  <span class="amount-compact">{{ formatAmount(row.totalStake) }} / {{ formatAmount(row.totalReturn) }}</span>
                </template>
              </el-table-column>
              <el-table-column :label="t('user.col.last_login')" width="108">
                <template #default="{ row }">
                  <el-tooltip v-if="row.lastLoginAt" :content="formatTime(row.lastLoginAt)" placement="top">
                    <span>{{ formatLastLogin(row.lastLoginAt) }}</span>
                  </el-tooltip>
                  <span v-else class="text-muted">{{ t('common.never_login') }}</span>
                </template>
              </el-table-column>
              <el-table-column :label="t('user.col.created')" width="108">
                <template #default="{ row }">
                  <el-tooltip :content="formatTime(row.createdAt)" placement="top">
                    <span>{{ formatLastLogin(row.createdAt) }}</span>
                  </el-tooltip>
                </template>
              </el-table-column>
              <el-table-column :label="t('common.actions')" width="340" fixed="right" align="center">
                <template #default="{ row }">
                  <div class="action-btns">
                    <el-button size="small" link type="primary" @click="openDetailPlayer(row.id)">{{ t('common.detail') }}</el-button>
                    <el-button size="small" link type="primary" @click="openEditPlayer(row.id)">{{ t('common.edit') }}</el-button>
                    <el-button size="small" link type="success" @click="openTransfer('deposit', row)">{{ t('common.topup') }}</el-button>
                    <el-button size="small" link type="warning" @click="openTransfer('withdraw', row)">{{ t('agent_portal.withdraw_btn_label') }}</el-button>
                    <el-button v-if="row.status === 'ACTIVE'" size="small" link type="warning" @click="toggleFreezePlayer(row)">{{ t('common.freeze') }}</el-button>
                    <el-button v-else size="small" link type="primary" @click="toggleFreezePlayer(row)">{{ t('common.unfreeze') }}</el-button>
                  </div>
                </template>
              </el-table-column>
            </el-table>
          </div>
          <div class="pager">
            <el-pagination
              v-model:current-page="playerPage"
              v-model:page-size="playerPageSize"
              :total="playerTotal"
              :page-sizes="[10, 20, 50, 100]"
              layout="total, sizes, prev, pager, next"
              background
              @current-change="onPlayerPageChange"
              @size-change="onPlayerSizeChange"
            />
          </div>
        </section>
      </el-tab-pane>

      <!-- ─── Tab: 一级代理 ─── -->
      <el-tab-pane :label="`${t('user.type.tier1_agent')} (${tier1Total})`" name="tier1Agents">
    <section class="list-panel agent-list-panel">
      <div class="list-panel-toolbar">
        <el-form inline class="list-chrome__grow">
          <el-form-item :label="t('common.keyword')">
            <el-input v-model="tier1Keyword" :placeholder="t('agent.filter.username_ph')" clearable style="width: 180px" @keyup.enter="searchTier1Agents" />
          </el-form-item>
          <el-form-item :label="t('common.status')">
            <el-select v-model="tier1FilterStatus" :placeholder="t('common.all')" clearable style="width: 120px">
              <el-option :label="t('user.status.ACTIVE')" value="ACTIVE" />
              <el-option :label="t('user.status.SUSPENDED')" value="SUSPENDED" />
            </el-select>
          </el-form-item>
          <el-form-item>
            <el-button type="primary" @click="searchTier1Agents">{{ t('common.search') }}</el-button>
          </el-form-item>
        </el-form>
        <div class="list-chrome__actions">
          <el-button type="primary" @click="openCreateTier1Agent">{{ t('agent.create_btn') }}</el-button>
        </div>
      </div>
      <div class="table-wrap">
        <el-table
          ref="tier1AgentTableRef"
          :data="tier1Agents"
          stripe
          row-key="userId"
          :row-class-name="expandableTableRowClassName"
          class="expandable-table"
          @expand-change="onExpandChange"
          @row-click="onTier1AgentRowClick"
        >
          <template #empty>
            <AdminTableEmpty />
          </template>

          <!-- Built-in expand column -->
          <el-table-column type="expand">
            <template #default="{ row }">
              <div class="expand-panel">
                <div v-if="expandLoading[row.userId]" class="expand-loading">
                  {{ t('common.loading') || '加载中...' }}
                </div>
                <div v-else class="expand-panel-body">
                  <div class="expand-section-header">
                    <div class="expand-section-title">{{ directPlayersTabLabel(row.username, getPlayers(row.userId).length) }}</div>
                    <el-button type="primary" size="small" @click="openCreatePlayer(row.userId)">{{ t('user.create_btn') }}</el-button>
                  </div>
                  <el-table :data="getPlayers(row.userId)" stripe class="inner-table">
                        <template #empty><AdminTableEmpty /></template>
                        <el-table-column prop="id" label="ID" width="60" />
                        <el-table-column prop="username" :label="t('user.col.username')" min-width="100" />
                        <el-table-column :label="t('common.status')" width="80">
                          <template #default="{ row: player }">
                            <el-tag :type="statusTagType(player.status)" size="small">{{ statusLabel(player.status) }}</el-tag>
                          </template>
                        </el-table-column>
                        <el-table-column :label="t('user.col.balance')" min-width="120" align="right">
                          <template #default="{ row: player }">
                            <el-tooltip :content="`${formatAmountFull(player.availableBalance)} / ${formatAmountFull(player.frozenBalance)}`" placement="top">
                              <span class="amount-compact">{{ formatAmount(player.availableBalance) }} / {{ formatAmount(player.frozenBalance) }}</span>
                            </el-tooltip>
                          </template>
                        </el-table-column>
                        <el-table-column prop="betCount" :label="t('user.col.bets')" width="56" align="center" />
                        <el-table-column :label="t('user.col.stake_payout')" min-width="100" align="right">
                          <template #default="{ row: player }">
                            <span class="amount-compact">{{ formatAmount(player.totalStake) }} / {{ formatAmount(player.totalReturn) }}</span>
                          </template>
                        </el-table-column>
                        <el-table-column :label="t('user.col.last_login')" width="100">
                          <template #default="{ row: player }">
                            <el-tooltip v-if="player.lastLoginAt" :content="formatTime(player.lastLoginAt)" placement="top">
                              <span>{{ formatLastLogin(player.lastLoginAt) }}</span>
                            </el-tooltip>
                            <span v-else class="text-muted">{{ t('common.never_login') }}</span>
                          </template>
                        </el-table-column>
                        <el-table-column :label="t('common.actions')" width="340" fixed="right" align="center">
                          <template #default="{ row: player }">
                            <div class="action-btns">
                              <el-button size="small" link type="primary" @click="openDetailPlayer(player.id)">{{ t('common.detail') }}</el-button>
                              <el-button size="small" link type="primary" @click="openEditPlayer(player.id)">{{ t('common.edit') }}</el-button>
                              <el-button size="small" link type="success" @click="openTransfer('deposit', player)">{{ t('common.topup') }}</el-button>
                              <el-button size="small" link type="warning" @click="openTransfer('withdraw', player)">{{ t('agent_portal.withdraw_btn_label') }}</el-button>
                              <el-button v-if="player.status === 'ACTIVE'" size="small" link type="warning" @click="toggleFreezePlayer(player)">{{ t('common.freeze') }}</el-button>
                              <el-button v-else size="small" link type="primary" @click="toggleFreezePlayer(player)">{{ t('common.unfreeze') }}</el-button>
                            </div>
                          </template>
                        </el-table-column>
                      </el-table>
                </div>
              </div>
            </template>
          </el-table-column>

          <el-table-column prop="userId" label="ID" width="72" />
          <el-table-column prop="username" :label="t('user.col.username')" min-width="140" />
          <el-table-column :label="t('common.status')" width="88">
            <template #default="{ row }">
              <el-tag :type="statusTagType(row.status)" size="small">{{ statusLabel(row.status) }}</el-tag>
            </template>
          </el-table-column>
          <el-table-column prop="level" :label="t('agent.col.level')" width="60" align="center">
            <template #default="{ row }">L{{ row.level }}</template>
          </el-table-column>
          <el-table-column :label="t('agent.col.credit')" min-width="168" align="right">
            <template #default="{ row }">
              <el-tooltip :content="creditLineFull(row)" placement="top">
                <span class="amount-compact">{{ creditLine(row) }}</span>
              </el-tooltip>
            </template>
          </el-table-column>
          <el-table-column prop="directPlayerCount" :label="t('agent.col.direct_players')" width="80" align="center" />
          <el-table-column prop="childAgentCount" :label="t('agent.col.sub_agents')" width="80" align="center" />
          <el-table-column :label="t('agent.col.cashback')" width="80" align="right">
            <template #default="{ row }">{{ row.cashbackRate }}</template>
          </el-table-column>
          <el-table-column :label="t('common.actions')" width="400" fixed="right" align="center">
            <template #default="{ row }">
              <div class="action-btns" @click.stop>
                <el-button size="small" link type="primary" @click="openDetailAgent(row.userId)">{{ t('common.detail') }}</el-button>
                <el-button size="small" link type="primary" @click="openEditAgent(row.userId)">{{ t('common.edit') }}</el-button>
                <el-button size="small" link type="primary" @click="openCredit(row.userId)">{{ t('common.adjust_credit') }}</el-button>
                <el-button size="small" link type="primary" @click="openCreateSubAgent(row.userId)">{{ t('agent.create_sub') }}</el-button>
                <el-button v-if="row.status === 'ACTIVE'" size="small" link type="warning" @click="toggleFreezeAgent(row)">{{ t('common.freeze') }}</el-button>
                <el-button v-else size="small" link type="primary" @click="toggleFreezeAgent(row)">{{ t('common.unfreeze') }}</el-button>
              </div>
            </template>
          </el-table-column>
        </el-table>
      </div>
      <div class="pager">
        <el-pagination
          v-model:current-page="tier1Page"
          v-model:page-size="tier1PageSize"
          :total="tier1Total"
          :page-sizes="[10, 20, 50, 100]"
          layout="total, sizes, prev, pager, next"
          background
          @current-change="onTier1PageChange"
          @size-change="onTier1SizeChange"
        />
      </div>
    </section>
      </el-tab-pane>

      <!-- ─── Tab: 二级代理 ─── -->
      <el-tab-pane :label="`${t('user.type.sub_agent')} (${tier2Total})`" name="tier2Agents">
        <section class="list-panel agent-list-panel">
          <div class="list-panel-toolbar">
            <el-form inline class="list-chrome__grow">
              <el-form-item :label="t('common.keyword')">
                <el-input v-model="tier2Keyword" :placeholder="t('agent.filter.username_ph')" clearable style="width: 180px" @keyup.enter="searchTier2Agents" />
              </el-form-item>
              <el-form-item :label="t('common.status')">
                <el-select v-model="tier2FilterStatus" :placeholder="t('common.all')" clearable style="width: 120px">
                  <el-option :label="t('user.status.ACTIVE')" value="ACTIVE" />
                  <el-option :label="t('user.status.SUSPENDED')" value="SUSPENDED" />
                </el-select>
              </el-form-item>
              <el-form-item>
                <el-button type="primary" @click="searchTier2Agents">{{ t('common.search') }}</el-button>
              </el-form-item>
            </el-form>
            <div class="list-chrome__actions">
              <el-button type="primary" @click="openCreateSubAgentFromToolbar">{{ t('agent.create_sub_btn') }}</el-button>
            </div>
          </div>
          <div class="table-wrap">
            <el-table
              ref="tier2AgentTableRef"
              :data="tier2Agents"
              stripe
              row-key="userId"
              :row-class-name="expandableTableRowClassName"
              class="expandable-table"
              @expand-change="onExpandChange"
              @row-click="onTier2AgentRowClick"
            >
              <template #empty>
                <AdminTableEmpty />
              </template>
              <el-table-column type="expand">
                <template #default="{ row }">
                  <div class="expand-panel">
                    <div v-if="expandLoading[row.userId]" class="expand-loading">{{ t('common.loading') }}</div>
                    <div v-else class="expand-panel-body">
                      <div class="expand-section-header">
                        <div class="expand-section-title">{{ directPlayersTabLabel(row.username, getPlayers(row.userId).length) }}</div>
                        <el-button type="primary" size="small" @click="openCreatePlayer(row.userId)">{{ t('user.create_btn') }}</el-button>
                      </div>
                      <el-table :data="getPlayers(row.userId)" stripe class="inner-table">
                        <template #empty><AdminTableEmpty /></template>
                        <el-table-column prop="id" label="ID" width="60" />
                        <el-table-column prop="username" :label="t('user.col.username')" min-width="100" />
                        <el-table-column :label="t('common.status')" width="80">
                          <template #default="{ row: player }">
                            <el-tag :type="statusTagType(player.status)" size="small">{{ statusLabel(player.status) }}</el-tag>
                          </template>
                        </el-table-column>
                        <el-table-column :label="t('user.col.balance')" min-width="120" align="right">
                          <template #default="{ row: player }">
                            <span class="amount-compact">{{ formatAmount(player.availableBalance) }} / {{ formatAmount(player.frozenBalance) }}</span>
                          </template>
                        </el-table-column>
                        <el-table-column :label="t('common.actions')" width="340" fixed="right" align="center">
                          <template #default="{ row: player }">
                            <div class="action-btns">
                              <el-button size="small" link type="primary" @click="openDetailPlayer(player.id)">{{ t('common.detail') }}</el-button>
                              <el-button size="small" link type="primary" @click="openEditPlayer(player.id)">{{ t('common.edit') }}</el-button>
                              <el-button size="small" link type="success" @click="openTransfer('deposit', player)">{{ t('common.topup') }}</el-button>
                              <el-button size="small" link type="warning" @click="openTransfer('withdraw', player)">{{ t('agent_portal.withdraw_btn_label') }}</el-button>
                            </div>
                          </template>
                        </el-table-column>
                      </el-table>
                    </div>
                  </div>
                </template>
              </el-table-column>
              <el-table-column prop="userId" label="ID" width="72" />
              <el-table-column prop="username" :label="t('user.col.username')" min-width="120" />
              <el-table-column :label="t('user.type.tier1_agent')" min-width="120">
                <template #default="{ row }">{{ row.parentUsername ?? '—' }}</template>
              </el-table-column>
              <el-table-column :label="t('common.status')" width="88">
                <template #default="{ row }">
                  <el-tag :type="statusTagType(subAgentAccountStatus(row))" size="small">{{ statusLabel(subAgentAccountStatus(row)) }}</el-tag>
                </template>
              </el-table-column>
              <el-table-column :label="t('agent.col.credit')" min-width="168" align="right">
                <template #default="{ row }">
                  <el-tooltip :content="creditLineFull(row)" placement="top">
                    <span class="amount-compact">{{ creditLine(row) }}</span>
                  </el-tooltip>
                </template>
              </el-table-column>
              <el-table-column prop="directPlayerCount" :label="t('agent.col.direct_players')" width="80" align="center" />
              <el-table-column :label="t('common.actions')" width="340" fixed="right" align="center">
                <template #default="{ row }">
                  <div class="action-btns" @click.stop>
                    <el-button size="small" link type="primary" @click="openDetailAgent(row.userId)">{{ t('common.detail') }}</el-button>
                    <el-button size="small" link type="primary" @click="openEditAgent(row.userId)">{{ t('common.edit') }}</el-button>
                    <el-button size="small" link type="primary" @click="openCredit(row.userId)">{{ t('common.adjust_credit') }}</el-button>
                    <el-button v-if="subAgentAccountStatus(row) === 'ACTIVE'" size="small" link type="warning" @click="toggleFreezeAgent(row)">{{ t('common.freeze') }}</el-button>
                    <el-button v-else size="small" link type="primary" @click="toggleFreezeAgent(row)">{{ t('common.unfreeze') }}</el-button>
                  </div>
                </template>
              </el-table-column>
            </el-table>
          </div>
          <div class="pager">
            <el-pagination
              v-model:current-page="tier2Page"
              v-model:page-size="tier2PageSize"
              :total="tier2Total"
              :page-sizes="[10, 20, 50, 100]"
              layout="total, sizes, prev, pager, next"
              background
              @current-change="onTier2PageChange"
              @size-change="onTier2SizeChange"
            />
          </div>
        </section>
      </el-tab-pane>
    </el-tabs>

    <!-- ═══════════ DIALOGS ═══════════ -->

    <!-- ── Create (unified) ── -->
    <el-dialog v-model="createVisible" :title="createDialogTitle" width="520px" destroy-on-close class="create-account-dialog">
      <el-form label-width="100px">
        <el-form-item :label="t('user.col.username')" required>
          <el-input
            v-model="createForm.username"
            :placeholder="createAccountMode === 0 ? t('user.ph.username_player') : t('user.ph.username_unique')"
          />
          <div v-if="createAccountMode === 0" class="field-hint">{{ t('user.hint.username_player') }}</div>
        </el-form-item>
        <el-form-item :label="t('user.field.password')" required>
          <el-input v-model="createForm.password" type="text" autocomplete="off" />
        </el-form-item>
        <el-form-item :label="t('user.field.confirm_password')" required>
          <el-input v-model="createForm.confirmPassword" type="text" autocomplete="off" />
        </el-form-item>

        <!-- 玩家：从代理行/展开区进入时锁定所属代理 -->
        <el-form-item v-if="createAccountMode === 0 && createParentLocked" :label="t('user.filter.agent')">
          <el-tag type="info" class="account-type-tag">{{ resolveCreateParentLabel(createParentAgentId) }}</el-tag>
          <div class="field-hint">{{ t('agent.hint.creating_under_agent') }}</div>
        </el-form-item>

        <!-- 玩家：从玩家 Tab 进入时可选择一级/二级代理 -->
        <template v-if="createAccountMode === 0 && !createParentLocked">
          <el-form-item :label="t('user.filter.agent')">
            <el-select v-model="createForm.parentId" :placeholder="t('user.ph.no_agent')" clearable style="width: 100%">
              <el-option v-for="a in agentOptions" :key="a.id" :label="agentOptionLabel(a)" :value="a.id" />
            </el-select>
            <div class="field-hint">{{ t('user.hint.no_agent') }}</div>
          </el-form-item>
        </template>

        <!-- 二级代理：从一级代理行进入时锁定上级 -->
        <el-form-item v-if="createAccountMode === 2 && createParentLocked" :label="t('user.type.tier1_agent')">
          <el-tag type="info" class="account-type-tag">{{ resolveCreateParentLabel(createParentAgentId) }}</el-tag>
          <div class="field-hint">{{ t('agent.hint.creating_under_agent') }}</div>
        </el-form-item>

        <!-- 二级代理：从二级 Tab 进入时选择一级代理 -->
        <template v-if="createAccountMode === 2 && !createParentLocked">
          <el-form-item :label="t('user.type.tier1_agent')" required>
            <el-select v-model="createParentAgentId" :placeholder="t('user.filter.agent_ph')" style="width: 100%">
              <el-option v-for="a in tier1AgentOptions" :key="a.id" :label="agentOptionLabel(a)" :value="a.id" />
            </el-select>
            <div class="field-hint">{{ t('agent.hint.sub_agent_parent') }}</div>
          </el-form-item>
        </template>

        <!-- 代理字段（一级 / 二级） -->
        <template v-if="createAccountMode === 1 || createAccountMode === 2">
          <el-form-item :label="t('agent.field.credit_limit')" required>
            <el-input-number v-model="createForm.creditLimit" :min="0" :step="10000" style="width: 100%" />
            <div class="field-hint">{{ t('agent.hint.credit_limit') }}</div>
          </el-form-item>
          <el-form-item :label="t('agent.field.cashback_rate')">
            <el-input-number v-model="createForm.cashbackRate" :min="0" :max="1" :step="0.001" :precision="4" style="width: 100%" />
            <div class="field-hint">{{ t('agent.hint.cashback_example') }}</div>
          </el-form-item>
          <el-form-item :label="t('agent.field.max_single_deposit')">
            <el-input-number v-model="createForm.maxSingleDeposit" :min="0" :step="100" style="width: 100%" />
            <div class="field-hint">{{ t('agent.hint.deposit_limit_empty') }}</div>
          </el-form-item>
          <el-form-item :label="t('agent.field.max_daily_deposit')">
            <el-input-number v-model="createForm.maxDailyDeposit" :min="0" :step="1000" style="width: 100%" />
            <div class="field-hint">{{ t('agent.hint.deposit_limit_empty') }}</div>
          </el-form-item>
        </template>

        <el-form-item :label="t('user.field.phone')">
          <el-input v-model="createForm.phone" :placeholder="t('common.optional')" />
        </el-form-item>
        <el-form-item :label="t('user.field.email')">
          <el-input v-model="createForm.email" :placeholder="t('common.optional')" />
        </el-form-item>

        <!-- Player-only: initial balance -->
        <template v-if="createAccountMode === 0">
          <el-form-item :label="t('user.field.initial_balance')">
            <el-input-number v-model="createForm.initialDeposit" :min="0" :step="100" style="width: 100%" />
            <div class="field-hint">{{ t('user.hint.initial_balance') }}</div>
          </el-form-item>
          <el-form-item :label="t('user.field.deposit_remark')">
            <el-input v-model="createForm.remark" :placeholder="t('user.ph.remark_initial')" />
          </el-form-item>
        </template>
      </el-form>
      <template #footer>
        <el-button @click="createVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" :loading="createLoading" @click="submitCreate">{{ t('user.btn.create') }}</el-button>
      </template>
    </el-dialog>

    <!-- ── Edit Player ── -->
    <el-dialog v-model="editPlayerVisible" :title="t('user.dialog.edit')" width="480px" destroy-on-close class="user-edit-dialog">
      <el-form label-width="84px" size="small" class="compact-edit-form">
        <div class="edit-meta">
          <span>ID {{ editPlayerForm.id }}</span>
          <el-tag :type="statusTagType(editPlayerForm.status)" size="small">{{ statusLabel(editPlayerForm.status) }}</el-tag>
        </div>
        <el-form-item :label="t('user.col.username')">
          <el-input v-model="editPlayerForm.username" :placeholder="t('user.ph.username_player')" />
          <div class="field-hint">{{ t('user.hint.username_player') }}</div>
        </el-form-item>
        <div class="password-mgmt-block">
          <div class="block-title">{{ t('user.section.password_mgmt') }}</div>
          <el-form-item :label="t('user.field.current_password')">
            <span v-if="editPlayerForm.managedPassword" class="password-plain">{{ editPlayerForm.managedPassword }}</span>
            <span v-else class="password-empty">—</span>
          </el-form-item>
          <p v-if="!editPlayerForm.managedPassword" class="field-hint block-hint">{{ t('user.hint.password_reset_to_view') }}</p>
          <el-form-item :label="t('user.field.reset_password')">
            <el-input v-model="editPlayerForm.newPassword" type="text" autocomplete="off" :placeholder="t('user.ph.reset_password_short')" />
          </el-form-item>
        </div>
        <el-form-item :label="t('user.col.agent')">
          <el-tag size="small" type="info" class="affiliation-tag">{{ affiliationLabel(editPlayerForm) }}</el-tag>
          <div class="field-hint">{{ t('user.hint.agent_readonly') }}</div>
        </el-form-item>
        <el-form-item :label="t('user.field.phone')">
          <el-input v-model="editPlayerForm.phone" :placeholder="t('common.optional')" />
        </el-form-item>
        <el-form-item :label="t('user.field.email')">
          <el-input v-model="editPlayerForm.email" :placeholder="t('common.optional')" />
        </el-form-item>
        <el-descriptions :column="2" size="small" border class="edit-stats">
          <el-descriptions-item :label="t('user.field.available')">{{ formatAmount(editPlayerForm.availableBalance) }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.frozen_balance')">{{ formatAmount(editPlayerForm.frozenBalance) }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.bets_summary')">{{ t('user.bets_edit_value', { n: editPlayerForm.betCount, stake: formatAmount(editPlayerForm.totalStake) }) }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.total_payout')">{{ formatAmount(editPlayerForm.totalReturn) }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.col.last_login')" :span="2">
            {{ editPlayerForm.lastLoginAt ? formatTime(editPlayerForm.lastLoginAt) : t('common.never_login') }}
            · {{ t('user.login_fail_value', { n: editPlayerForm.loginFailCount }) }}
          </el-descriptions-item>
        </el-descriptions>
      </el-form>
      <template #footer>
        <el-button size="small" @click="editPlayerVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button size="small" type="primary" :loading="editPlayerLoading" @click="submitEditPlayer">{{ t('user.btn.save_profile') }}</el-button>
      </template>
    </el-dialog>

    <!-- ── Edit Agent ── -->
    <el-dialog v-model="editAgentVisible" :title="t('agent.dialog.edit')" width="520px" destroy-on-close class="agent-edit-dialog">
      <el-form label-width="88px" size="small" class="compact-edit-form">
        <div class="edit-meta">
          <span>ID {{ editAgentForm.id }}</span>
          <el-tag :type="statusTagType(editAgentForm.status)" size="small">{{ statusLabel(editAgentForm.status) }}</el-tag>
          <el-tag size="small" type="info">L{{ editAgentForm.level }}</el-tag>
          <span v-if="editAgentForm.parentUsername" class="text-muted">{{ t('user.col.agent') }}: {{ editAgentForm.parentUsername }}</span>
        </div>
        <el-form-item :label="t('user.col.username')">
          <el-input v-model="editAgentForm.username" :placeholder="t('user.ph.username_unique')" />
        </el-form-item>
        <div class="password-mgmt-block">
          <div class="block-title">{{ t('user.section.password_mgmt') }}</div>
          <el-form-item :label="t('user.field.current_password')">
            <span v-if="editAgentForm.managedPassword" class="password-plain">{{ editAgentForm.managedPassword }}</span>
            <span v-else class="password-empty">—</span>
          </el-form-item>
          <p v-if="!editAgentForm.managedPassword" class="field-hint block-hint">{{ t('user.hint.password_reset_to_view') }}</p>
          <el-form-item :label="t('user.field.reset_password')">
            <el-input v-model="editAgentForm.newPassword" type="text" autocomplete="off" :placeholder="t('user.ph.reset_password_short')" />
          </el-form-item>
        </div>
        <el-form-item :label="t('user.field.account_status')">
          <el-radio-group v-model="editAgentForm.status">
            <el-radio value="ACTIVE">{{ t('user.status.ACTIVE') }}</el-radio>
            <el-radio value="SUSPENDED">{{ t('user.status.SUSPENDED') }}</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item :label="t('agent.field.cashback_rate')">
          <el-input-number v-model="editAgentForm.cashbackRate" :min="0" :max="1" :step="0.001" :precision="4" style="width: 100%" />
        </el-form-item>
        <el-form-item :label="t('agent.field.max_single_deposit')">
          <el-input-number v-model="editAgentForm.maxSingleDeposit" :min="0" :step="100" style="width: 100%" />
          <div class="field-hint">{{ t('agent.hint.deposit_limit_empty') }}</div>
        </el-form-item>
        <el-form-item :label="t('agent.field.max_daily_deposit')">
          <el-input-number v-model="editAgentForm.maxDailyDeposit" :min="0" :step="1000" style="width: 100%" />
          <div class="field-hint">{{ t('agent.hint.deposit_limit_empty') }}</div>
        </el-form-item>
        <el-form-item :label="t('user.field.phone')">
          <el-input v-model="editAgentForm.phone" :placeholder="t('common.optional')" />
        </el-form-item>
        <el-form-item :label="t('user.field.email')">
          <el-input v-model="editAgentForm.email" :placeholder="t('common.optional')" />
        </el-form-item>
        <el-descriptions :column="2" size="small" border class="edit-stats">
          <el-descriptions-item :label="t('agent.field.credit_limit')">{{ formatAmount(editAgentForm.creditLimit) }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.field.available_credit')">{{ formatAmount(editAgentForm.availableCredit) }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.field.used_credit')">{{ formatAmount(editAgentForm.usedCredit) }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.col.direct_players')">{{ editAgentForm.directPlayerCount }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.col.sub_agents')">{{ editAgentForm.childAgentCount }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.col.last_login')" :span="2">
            {{ editAgentForm.lastLoginAt ? formatTime(editAgentForm.lastLoginAt) : t('common.never_login') }}
            · {{ t('user.login_fail_value', { n: editAgentForm.loginFailCount }) }}
          </el-descriptions-item>
        </el-descriptions>
      </el-form>
      <template #footer>
        <el-button size="small" @click="editAgentVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button size="small" type="primary" :loading="editAgentLoading" @click="submitEditAgent">{{ t('user.btn.save_profile') }}</el-button>
      </template>
    </el-dialog>

    <!-- ── Player transfer (deposit / withdraw) ── -->
    <el-dialog v-model="transferVisible" :title="transferTitle()" width="520px" destroy-on-close>
      <WalletTransferContext
        :context="transferContext"
        :mode="transferType"
        :loading="transferContextLoading"
      />
      <el-form label-width="88px">
        <el-form-item :label="t('common.col_id')">
          <span>{{ transferTarget?.id }}</span>
        </el-form-item>
        <el-form-item :label="t('user.field.amount')" :error="transferAmountCapError">
          <el-input-number
            v-model="transferAmount"
            :min="transferAmountRange.min"
            :disabled="transferAmountDisabled"
            :step="10"
            :precision="2"
            style="width: 100%"
          />
        </el-form-item>
        <el-form-item :label="t('user.field.remark')">
          <el-input v-model="transferRemark" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="transferVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button
          type="primary"
          :loading="transferLoading"
          :disabled="transferAmountDisabled || transferAmountExceedsCap"
          @click="submitTransfer"
        >
          {{ t('common.confirm') }}
        </el-button>
      </template>
    </el-dialog>

    <!-- ── Credit ── -->
    <el-dialog v-model="creditVisible" :title="t('agent.dialog.credit')" width="520px" destroy-on-close>
      <AgentCreditContext
        :context="creditContext"
        :loading="creditContextLoading"
        :adjust-amount="creditForm.amount"
      />
      <el-form label-width="88px">
        <el-form-item :label="t('agent.field.agent_id')">
          <el-input :model-value="editingId" disabled />
        </el-form-item>
        <el-form-item :label="t('agent.field.adjust_amount')">
          <el-input-number v-model="creditForm.amount" :step="1000" style="width: 100%" />
          <div class="field-hint">{{ t('agent.hint.credit_adjust') }}</div>
        </el-form-item>
        <el-form-item :label="t('user.field.remark')">
          <el-input v-model="creditForm.remark" :placeholder="t('agent.hint.credit_remark')" />
        </el-form-item>
      </el-form>
      <template #footer>
        <el-button @click="creditVisible = false">{{ t('common.cancel') }}</el-button>
        <el-button type="primary" :loading="creditLoading" @click="submitCredit">{{ t('agent.btn.confirm_adjust') }}</el-button>
      </template>
    </el-dialog>

    <!-- ── Player Detail ── -->
    <el-dialog v-model="detailPlayerVisible" :title="t('user.dialog.detail')" width="560px" destroy-on-close>
      <template v-if="playerDetail">
        <el-descriptions :column="2" border size="small">
          <el-descriptions-item :label="t('common.col_id')">{{ playerDetail.id }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.col.username')">{{ playerDetail.username }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.current_password')">{{ playerDetail.managedPassword ?? '—' }}</el-descriptions-item>
          <el-descriptions-item v-if="!playerDetail.managedPassword" :span="2">
            <span class="field-hint">{{ t('user.hint.password_reset_to_view') }}</span>
          </el-descriptions-item>
          <el-descriptions-item :label="t('common.status')">
            <el-tag :type="statusTagType(playerDetail.status)" size="small">{{ statusLabel(playerDetail.status) }}</el-tag>
          </el-descriptions-item>
          <el-descriptions-item :label="t('user.col.agent')">{{ affiliationLabel(playerDetail) }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.available')">
            {{ formatAmount(playerDetail.availableBalance) }}
            <span v-if="shouldCompact(playerDetail.availableBalance)" class="amount-full-hint">（{{ formatAmountFull(playerDetail.availableBalance) }}）</span>
          </el-descriptions-item>
          <el-descriptions-item :label="t('user.field.frozen_balance')">
            {{ formatAmount(playerDetail.frozenBalance) }}
            <span v-if="shouldCompact(playerDetail.frozenBalance)" class="amount-full-hint">（{{ formatAmountFull(playerDetail.frozenBalance) }}）</span>
          </el-descriptions-item>
          <el-descriptions-item :label="t('user.field.phone')">{{ playerDetail.phone ?? '—' }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.email')">{{ playerDetail.email ?? '—' }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.bet_count')">{{ playerDetail.betCount }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.total_stake')">{{ formatAmount(playerDetail.totalStake) }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.total_payout')">{{ formatAmount(playerDetail.totalReturn) }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.col.last_login')">
            {{ playerDetail.lastLoginAt ? formatTime(playerDetail.lastLoginAt) : t('common.never_login') }}
          </el-descriptions-item>
          <el-descriptions-item :label="t('user.field.login_fail')">{{ t('user.login_fail_value', { n: playerDetail.loginFailCount }) }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.registered_at')" :span="2">{{ formatTime(playerDetail.createdAt) }}</el-descriptions-item>
        </el-descriptions>
      </template>
    </el-dialog>

    <!-- ── Agent Detail ── -->
    <el-dialog v-model="detailAgentVisible" :title="t('agent.dialog.detail')" width="640px" destroy-on-close>
      <template v-if="agentDetail">
        <el-descriptions :column="2" border size="small" class="detail-block">
          <el-descriptions-item :label="t('common.col_id')">{{ agentDetail.userId }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.col.username')">{{ agentDetail.username }}</el-descriptions-item>
          <el-descriptions-item :label="t('common.status')">
            <el-tag :type="statusTagType(agentDetail.status)" size="small">{{ statusLabel(agentDetail.status) }}</el-tag>
          </el-descriptions-item>
          <el-descriptions-item :label="t('agent.col.level')">L{{ agentDetail.level }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.field.credit_limit')">
            {{ formatAmount(agentDetail.creditLimit) }}
            <span v-if="shouldCompact(agentDetail.creditLimit)" class="amount-full-hint">（{{ formatAmountFull(agentDetail.creditLimit) }}）</span>
          </el-descriptions-item>
          <el-descriptions-item :label="t('agent.field.used_credit')">
            {{ formatAmount(agentDetail.usedCredit) }}
            <span v-if="shouldCompact(agentDetail.usedCredit)" class="amount-full-hint">（{{ formatAmountFull(agentDetail.usedCredit) }}）</span>
          </el-descriptions-item>
          <el-descriptions-item :label="t('agent.field.available_credit')">
            {{ formatAmount(agentDetail.availableCredit) }}
            <span v-if="shouldCompact(agentDetail.availableCredit)" class="amount-full-hint">（{{ formatAmountFull(agentDetail.availableCredit) }}）</span>
          </el-descriptions-item>
          <el-descriptions-item :label="t('agent.col.direct_players')">{{ agentDetail.directPlayerCount }} {{ t('common.people') }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.col.sub_agents')">{{ agentDetail.childAgentCount }} {{ t('common.people') }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.field.player_liability')">{{ formatAmount(agentDetail.directPlayerLiability) }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.field.sub_agent_exposure')">{{ formatAmount(agentDetail.childAgentExposure) }}</el-descriptions-item>
          <el-descriptions-item :label="t('agent.col.cashback')">{{ agentDetail.cashbackRate }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.phone')">{{ agentDetail.phone ?? '—' }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.field.email')">{{ agentDetail.email ?? '—' }}</el-descriptions-item>
          <el-descriptions-item :label="t('user.col.last_login')" :span="2">
            {{ agentDetail.lastLoginAt ? formatTime(agentDetail.lastLoginAt) : t('common.never_login') }}
          </el-descriptions-item>
          <el-descriptions-item :label="t('agent.col.created')" :span="2">{{ formatTime(agentDetail.createdAt) }}</el-descriptions-item>
        </el-descriptions>

        <div class="section-title section-title--row">
          <span>{{ t('agent.section.credit_log') }}</span>
          <el-button
            v-if="agentDetail"
            link
            type="primary"
            @click="router.push({ path: '/agent-credit-transactions', query: { agentId: agentDetail.userId } })"
          >
            {{ t('agent.credit_tx.view_all') }}
          </el-button>
        </div>
        <el-table :data="agentDetail.recentCreditTransactions" size="small" stripe :empty-text="t('agent.col.no_records')">
          <el-table-column :label="t('agent.col.credit_type')" width="80">
            <template #default="{ row }">{{ creditTypeLabel(row.transactionType) }}</template>
          </el-table-column>
          <el-table-column :label="t('agent.col.credit_change')" width="96" align="right">
            <template #default="{ row }">
              <el-tooltip :content="formatAmountFull(row.amount)" placement="top">
                <span>{{ formatAmount(row.amount) }}</span>
              </el-tooltip>
            </template>
          </el-table-column>
          <el-table-column :label="t('agent.col.credit_after')" width="96" align="right">
            <template #default="{ row }">
              <el-tooltip :content="formatAmountFull(row.creditAfter)" placement="top">
                <span>{{ formatAmount(row.creditAfter) }}</span>
              </el-tooltip>
            </template>
          </el-table-column>
          <el-table-column prop="remark" :label="t('user.field.remark')" min-width="120" show-overflow-tooltip />
          <el-table-column :label="t('audit.col.time')" min-width="150">
            <template #default="{ row }">{{ formatTime(row.createdAt) }}</template>
          </el-table-column>
        </el-table>
      </template>
    </el-dialog>
  </div>
</template>

<style scoped>
.agent-mgr-page > .agent-list-panel,
.agent-mgr-page > .mgr-top-tabs {
  flex: 1;
  min-height: 0;
}
.agent-mgr-page > .mgr-top-tabs :deep(.el-tabs__content) {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.agent-mgr-page > .mgr-top-tabs :deep(.el-tab-pane) {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.player-list-panel,
.agent-list-panel {
  flex: 1;
  min-height: 0;
  display: flex;
  flex-direction: column;
}
.mgr-top-tabs :deep(.el-tabs__header) {
  margin-bottom: 8px;
}
.mgr-top-tabs :deep(.el-tabs__item) {
  font-size: 14px;
  font-weight: 500;
}

/* ─── Table toolbar ─── */
.list-panel-toolbar {
  flex-shrink: 0;
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 12px;
  padding: 10px 0 8px;
  border-bottom: 1px solid rgba(255, 255, 255, 0.06);
  --list-chrome-control-h: 32px;
  --el-component-size: 32px;
}
.list-panel-toolbar .list-chrome__actions {
  flex-shrink: 0;
}
.list-panel-toolbar :deep(.el-form-item) {
  margin-bottom: 0 !important;
  margin-right: 12px;
}
.list-panel-toolbar :deep(.el-input__wrapper),
.list-panel-toolbar :deep(.el-select__wrapper) {
  height: var(--list-chrome-control-h) !important;
  min-height: var(--list-chrome-control-h) !important;
}
.list-panel-toolbar :deep(.el-button:not(.is-link)) {
  height: var(--list-chrome-control-h) !important;
  min-height: var(--list-chrome-control-h) !important;
}

/* ─── Expansion ─── */
.expand-panel {
  margin: 4px 0 8px;
  padding: 12px 14px 14px;
  background: #141414;
  border: 1px solid #2a2a2a;
  border-left: 3px solid rgba(47, 181, 106, 0.45);
  border-radius: 8px;
}
.expand-loading {
  text-align: center;
  padding: 16px;
  color: #888;
  font-size: 13px;
}
.expand-section-header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 6px;
}
.expand-section-title {
  font-size: 13px;
  font-weight: 600;
  color: #888;
}
.expandable-table :deep(.row-expandable) {
  cursor: pointer;
}
.nested-table {
  margin-bottom: 4px;
}
.inner-tabs {
  margin-top: 0;
}
.inner-tabs :deep(.el-tabs__header) {
  margin-bottom: 4px;
}
.inner-tabs :deep(.el-tabs__nav-wrap) {
  margin-bottom: 0;
}
.inner-tabs :deep(.el-tabs__item) {
  height: 34px;
  line-height: 34px;
  font-size: 13px;
  font-weight: 500;
  color: #888;
  padding: 0 14px;
}
.inner-tabs :deep(.el-tabs__item.is-active) {
  color: #d4fde5;
  font-weight: 700;
}
.inner-tabs :deep(.el-tabs__active-bar) {
  background-color: var(--green-bright);
  height: 2px;
}
.inner-tabs :deep(.el-tabs__content) {
  padding: 0;
}
.inner-table {
  border-radius: 6px;
}
.inner-table :deep(.el-table__cell) {
  font-size: 13px;
}
.account-type-tag {
  font-size: 13px;
  font-weight: 600;
}
.expandable-table :deep(.row-expandable) {
  cursor: pointer;
}
.action-btns {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 4px;
  flex-wrap: nowrap;
  white-space: nowrap;
}

/* ─── Inherited from old pages ─── */
.settings-form :deep(.el-form-item) {
  margin-bottom: 0;
  margin-right: 12px;
}
.field-hint { font-size: 12px; color: #888; margin-top: 4px; }
.amount-compact { white-space: nowrap; font-variant-numeric: tabular-nums; cursor: default; }
.affiliation-tag {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
}
.amount-full-hint { font-size: 11px; color: #666; margin-left: 4px; }
.text-muted { color: #666; font-size: 12px; }
.password-mgmt-block {
  margin: 4px 0 10px;
  padding: 10px 12px;
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: 8px;
  background: rgba(0, 0, 0, 0.15);
}
.block-title {
  font-size: 12px;
  font-weight: 700;
  color: #e8a84a;
  margin-bottom: 8px;
  letter-spacing: 0.04em;
}
.password-plain {
  font-family: ui-monospace, monospace;
  font-size: 14px;
  font-weight: 600;
  color: #f0d090;
  letter-spacing: 0.06em;
}
.password-empty { color: #666; }
.block-hint { margin: -4px 0 8px; }
.edit-meta {
  display: flex;
  align-items: center;
  gap: 10px;
  margin-bottom: 10px;
  font-size: 12px;
  color: #888;
}
.compact-edit-form :deep(.el-form-item) {
  margin-bottom: 10px;
}
.edit-stats { margin-top: 4px; }
.list-settings-block--danger {
  margin-top: 12px;
  padding-top: 12px;
  border-top: 1px dashed rgba(245, 108, 108, 0.35);
}
.list-settings-hint {
  font-size: 12px;
  color: #888;
  margin: 0 0 10px;
  line-height: 1.5;
}
.reset-db-alert { margin-bottom: 10px; }
.detail-block { margin-bottom: 16px; }
.section-title {
  font-size: 13px;
  font-weight: 600;
  color: #666;
  margin-bottom: 8px;
}

.section-title--row {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: 8px;
}
</style>

<style>
/* 玩家列表「冻结」：橙黄底白字 */
.agent-mgr-page .el-button.is-link.el-button--warning {
  color: #ffffff !important;
  background: linear-gradient(165deg, #e8a84a 0%, #c47a18 42%, #9a5c10 100%) !important;
  border: 1px solid rgba(232, 168, 74, 0.45) !important;
  border-radius: 6px !important;
  padding: 5px 11px !important;
  box-shadow: 0 1px 0 rgba(255, 255, 255, 0.12) inset, 0 1px 6px rgba(0, 0, 0, 0.35) !important;
  text-shadow: 0 1px 1px rgba(0, 0, 0, 0.2);
}
.agent-mgr-page .el-button.is-link.el-button--warning:hover,
.agent-mgr-page .el-button.is-link.el-button--warning:focus {
  color: #ffffff !important;
  background: linear-gradient(165deg, #f0bc62 0%, #d48a28 42%, #a86814 100%) !important;
  border-color: rgba(240, 188, 98, 0.55) !important;
}
</style>
