/**
 * E2E：超管玩家管理
 *
 * 链路：
 *  1. 创建玩家（site_code=demo, username/password）
 *  2. 用新建玩家登录 → 拿 token
 *  3. /admin/players/{id}/freeze → status=1
 *  4. 玩家用 frozen 账号登录 → 403 PlayerAccountSuspended
 *  5. /admin/players/{id}/unfreeze → status=0
 *  6. 玩家又能登录
 *  7. /admin/players 列表能找到新建玩家
 *  8. /admin/players/{id}/wallets 返回钱包列表
 *
 * 不测 destroy：避免把 e2e 自带的 demo_player 误删（player id 不固定）。
 */

import { test, expect, request as pwRequest } from '@playwright/test';
import { adminLoginViaBypass, fetchPlayerCaptcha, e2e } from './_helper';

const SITE_CODE = 'demo';
const CURRENCY = (process.env.LOTTERY_DEFAULT_CURRENCY ?? 'NPR').toUpperCase();
const PWD = '12345678';

function uniqueUsername(): string {
  // 玩家 username 规则 native 6-32 位字母数字下划线（参考 nativePlayerUsernameRules）
  return 'e2e_p_' + Math.random().toString(36).slice(2, 10);
}

async function adminCtxOf(token: string) {
  return pwRequest.newContext({
    extraHTTPHeaders: { Authorization: `Bearer ${token}` },
  });
}

async function playerLoginCtx(siteCode: string, username: string, password: string, captchaKey: string) {
  const ctx = await pwRequest.newContext();
  const r = await ctx.post('/api/v1/player/auth/login', {
    data: {
      site_code: siteCode,
      username,
      password,
      captcha_key: captchaKey,
      captcha_code: 'LOTTERY_E2E_BYPASS',
    },
  });
  return { ctx, status: r.status(), body: (await r.json().catch(() => ({}))) as any };
}

test('超管创建玩家 + 玩家登录成功', async () => {
  const session = await adminLoginViaBypass();
  const admin = await adminCtxOf(session.accessToken);
  const username = uniqueUsername();

  const r = await admin.post('/api/v1/admin/players', {
    data: {
      site_code: SITE_CODE,
      site_player_id: 'e2e-' + username,
      username,
      password: PWD,
      default_currency: CURRENCY,
      status: 0,
    },
  });
  expect(r.ok(), `create player status=${r.status()}`).toBeTruthy();
  const created = (await r.json()) as any;
  expect(created.code).toBe(0);
  const playerId = created.data.id;
  expect(typeof playerId).toBe('number');
  await admin.dispose();

  // 玩家登录
  const cap = await fetchPlayerCaptcha();
  const { ctx, status, body } = await playerLoginCtx(SITE_CODE, username, PWD, cap.captcha_key);
  expect(status, `player login status=${status}`).toBe(200);
  expect(body.code).toBe(0);
  expect(body.data.player.username).toBe(username);
  await ctx.dispose();
});

test('超管 freeze → 玩家登录 403；unfreeze → 又能登录', async () => {
  const session = await adminLoginViaBypass();
  const admin = await adminCtxOf(session.accessToken);
  const username = uniqueUsername();

  // 创建
  const r = await admin.post('/api/v1/admin/players', {
    data: {
      site_code: SITE_CODE,
      site_player_id: 'e2e-' + username,
      username,
      password: PWD,
      default_currency: CURRENCY,
      status: 0,
    },
  });
  const created = (await r.json()) as any;
  const playerId = created.data.id;

  // freeze
  const fz = await admin.post(`/api/v1/admin/players/${playerId}/freeze`);
  expect(fz.ok(), `freeze status=${fz.status()}`).toBeTruthy();
  const fzBody = (await fz.json()) as any;
  expect(fzBody.data.status).toBe(1);
  await admin.dispose();

  // frozen 玩家登录应失败（player_account_suspended）
  const cap1 = await fetchPlayerCaptcha();
  const { ctx: ctx1, status: st1, body: b1 } = await playerLoginCtx(SITE_CODE, username, PWD, cap1.captcha_key);
  expect([200, 403]).toContain(st1);
  if (st1 === 200) {
    expect(b1.code).not.toBe(0);
  }
  await ctx1.dispose();

  // unfreeze
  const admin2 = await adminCtxOf(session.accessToken);
  const uf = await admin2.post(`/api/v1/admin/players/${playerId}/unfreeze`);
  expect(uf.ok(), `unfreeze status=${uf.status()}`).toBeTruthy();
  const ufBody = (await uf.json()) as any;
  expect(ufBody.data.status).toBe(0);
  await admin2.dispose();

  // 玩家又能登录
  const cap2 = await fetchPlayerCaptcha();
  const { ctx: ctx2, status: st2, body: b2 } = await playerLoginCtx(SITE_CODE, username, PWD, cap2.captcha_key);
  expect(st2, `player login after unfreeze status=${st2}`).toBe(200);
  expect(b2.code).toBe(0);
  await ctx2.dispose();
});

test('/admin/players 列表能找到新建玩家（按 username 搜索）', async () => {
  const session = await adminLoginViaBypass();
  const admin = await adminCtxOf(session.accessToken);
  const username = uniqueUsername();

  const r = await admin.post('/api/v1/admin/players', {
    data: {
      site_code: SITE_CODE,
      site_player_id: 'e2e-' + username,
      username,
      password: PWD,
      default_currency: CURRENCY,
      status: 0,
    },
  });
  const created = (await r.json()) as any;
  const playerId = created.data.id;

  // 列表搜索
  const list = await admin.get(`/api/v1/admin/players?keyword=${encodeURIComponent(username)}&size=20`);
  expect(list.ok(), `list status=${list.status()}`).toBeTruthy();
  const body = (await list.json()) as any;
  const items: any[] = body.data.items;
  expect(items.length).toBeGreaterThanOrEqual(1);
  const found = items.find((it) => it.id === playerId);
  expect(found).toBeTruthy();
  expect(found.username).toBe(username);
  await admin.dispose();
});

test('/admin/players/{id}/wallets 信用盘玩家返回空钱包列表', async () => {
  const session = await adminLoginViaBypass();
  const admin = await adminCtxOf(session.accessToken);
  const username = uniqueUsername();

  const r = await admin.post('/api/v1/admin/players', {
    data: {
      site_code: SITE_CODE,
      site_player_id: 'e2e-' + username,
      username,
      password: PWD,
      default_currency: CURRENCY,
      status: 0,
    },
  });
  const created = (await r.json()) as any;
  const playerId = created.data.id;
  expect(created.data.funding_mode).toBe('credit');

  // 信用盘玩家登录不会开立 player_wallets
  const cap = await fetchPlayerCaptcha();
  const { ctx, status, body } = await playerLoginCtx(SITE_CODE, username, PWD, cap.captcha_key);
  expect(status).toBe(200);
  expect(body.code).toBe(0);
  await ctx.dispose();

  // 查 wallet
  const w = await admin.get(`/api/v1/admin/players/${playerId}/wallets`);
  expect(w.ok(), `wallets status=${w.status()}`).toBeTruthy();
  const wb = (await w.json()) as any;
  const wallets: any[] = wb.data.wallets ?? [];
  expect(wallets.length).toBe(0);
  await admin.dispose();
});

test('创建玩家缺 site_player_id → 422', async () => {
  const session = await adminLoginViaBypass();
  const admin = await adminCtxOf(session.accessToken);
  const username = uniqueUsername();

  const r = await admin.post('/api/v1/admin/players', {
    data: {
      site_code: SITE_CODE,
      username,
      default_currency: CURRENCY,
    },
  });
  expect([422, 400]).toContain(r.status());
  await admin.dispose();
});

test('创建玩家重复 username → 409/422 业务失败', async () => {
  const session = await adminLoginViaBypass();
  const admin = await adminCtxOf(session.accessToken);
  const username = uniqueUsername();

  // 第一次
  const r1 = await admin.post('/api/v1/admin/players', {
    data: {
      site_code: SITE_CODE,
      site_player_id: 'e2e-dup-' + username,
      username,
      password: PWD,
      default_currency: CURRENCY,
    },
  });
  expect(r1.ok()).toBeTruthy();

  // 第二次同 username（不同 site_player_id）
  const r2 = await admin.post('/api/v1/admin/players', {
    data: {
      site_code: SITE_CODE,
      site_player_id: 'e2e-dup2-' + username,
      username,
      password: PWD,
      default_currency: CURRENCY,
    },
  });
  // 业务失败，HTTP 200 + code 非 0 是常见；或直接 4xx
  const b2 = (await r2.json().catch(() => ({}))) as any;
  if (r2.status() === 200) {
    expect(b2.code).not.toBe(0);
  } else {
    expect([409, 422, 400, 500]).toContain(r2.status());
  }
  await admin.dispose();
});
