import { test, expect } from '../../utils/test-setup';

/**
 * 人才小程序登录 E2E 测试
 *
 * 测试人才用户通过小程序登录的功能，验证：
 * - 表单验证
 * - 登录失败场景
 * - 登录成功场景
 * - Token 持久性
 * - 退出登录
 *
 * @see {@link ../pages/mini/talent-mini.page.ts} TalentMiniPage
 * 测试用户信息（Story 12.3 创建）：
 * - 账号: 13800128219
 * - 密码: admin123
 */

/**
 * 创建测试用户的辅助函数
 *
 * 在独立的 browser context 中通过管理后台创建测试用户，
 * 避免与小程序登录测试共享 page 实例导致的冲突。
 *
 * @param browser Playwright browser 实例
 * @param userData 用户数据
 * @returns 创建的用户名和密码
 */
async function createTestUser(browser: typeof test['fixtures']['browser'], userData: {
  username: string;
  password: string;
  nickname?: string;
  disabilityPersonId?: number;
}): Promise<{ username: string; password: string }> {
  // 动态导入 AdminLoginPage 和 UserManagementPage，避免与小程序测试共享 context
  const { AdminLoginPage } = await import('../../pages/admin/login.page');
  const { UserManagementPage } = await import('../../pages/admin/user-management.page');

  // 创建独立的 browser context
  const adminContext = await browser.newContext();

  try {
    // 在独立 context 中创建 page
    const adminPage = await adminContext.newPage();

    // 创建管理后台 Page Objects
    const adminLoginPage = new AdminLoginPage(adminPage);
    const userManagementPage = new UserManagementPage(adminPage);

    // 登录管理后台
    await adminLoginPage.goto();
    await adminLoginPage.login('admin', 'admin123');

    // 导航到用户管理页面
    await userManagementPage.goto();

    // 创建测试用户（使用 TALENT 类型，人才用户）
    const result = await userManagementPage.createUser({
      username: userData.username,
      password: userData.password,
      nickname: userData.nickname || '测试人才用户',
      disabilityPersonId: userData.disabilityPersonId || 1,
    });

    // 验证创建成功
    expect(result.success).toBe(true);

    return { username: userData.username, password: userData.password };
  } finally {
    // 清理：关闭独立 context
    await adminContext.close();
  }
}

test.describe('人才小程序登录功能', () => {
  test.describe('表单验证测试 (AC3)', () => {
    test('不输入任何信息应该无法登录', async ({ talentMiniPage }) => {
      // 导航到登录页面
      await talentMiniPage.goto();

      // 不填写任何信息，直接点击登录按钮
      await talentMiniPage.clickLoginButton();

      // 等待表单验证完成
      await talentMiniPage.page.waitForTimeout(500);

      // 验证仍然在登录页面（未跳转）
      // Toast 消息在 headless 模式下可能不稳定，但页面不应该跳转
      const currentUrl = talentMiniPage.page.url();
      expect(currentUrl).toContain('/talent-mini');
      expect(currentUrl).toContain('/pages/login/index');

      // 验证未存储 token
      const token = await talentMiniPage.getToken();
      expect(token).toBeNull();
    });

    test('只输入账号不输入密码应该无法登录', async ({ talentMiniPage }) => {
      // 导航到登录页面
      await talentMiniPage.goto();

      // 只填写账号，不填写密码
      await talentMiniPage.fillIdentifier('13800128219');

      // 尝试点击登录按钮
      await talentMiniPage.clickLoginButton();

      // 等待表单验证完成
      await talentMiniPage.page.waitForTimeout(500);

      // 验证仍然在登录页面（未跳转）
      const currentUrl = talentMiniPage.page.url();
      expect(currentUrl).toContain('/talent-mini');
      expect(currentUrl).toContain('/pages/login/index');

      // 验证未存储 token
      const token = await talentMiniPage.getToken();
      expect(token).toBeNull();
    });

    test('只输入密码不输入账号应该无法登录', async ({ talentMiniPage }) => {
      // 导航到登录页面
      await talentMiniPage.goto();

      // 只填写密码，不填写账号
      await talentMiniPage.fillPassword('admin123');

      // 尝试点击登录按钮
      await talentMiniPage.clickLoginButton();

      // 等待表单验证完成
      await talentMiniPage.page.waitForTimeout(500);

      // 验证仍然在登录页面（未跳转）
      const currentUrl = talentMiniPage.page.url();
      expect(currentUrl).toContain('/talent-mini');
      expect(currentUrl).toContain('/pages/login/index');

      // 验证未存储 token
      const token = await talentMiniPage.getToken();
      expect(token).toBeNull();
    });
  });

  test.describe('登录失败测试 (AC2)', () => {
    test('使用不存在的用户名登录失败', async ({ talentMiniPage }) => {
      // 导航到登录页面
      await talentMiniPage.goto();

      // 使用不存在的用户名尝试登录
      const fakeUsername = '12345678901';
      await talentMiniPage.login(fakeUsername, 'password123');

      // 等待 API 响应
      await talentMiniPage.page.waitForTimeout(2000);

      // 验证仍然在登录页面（未跳转）
      const currentUrl = talentMiniPage.page.url();
      expect(currentUrl).toContain('/talent-mini');

      // 验证未存储 token
      const token = await talentMiniPage.getToken();
      expect(token).toBeNull();
    });

    test('使用错误的密码登录失败', async ({ talentMiniPage }) => {
      // 导航到登录页面
      await talentMiniPage.goto();

      // 使用存在的用户但错误的密码尝试登录
      await talentMiniPage.login('13800128219', 'wrongpassword');

      // 等待 API 响应
      await talentMiniPage.page.waitForTimeout(2000);

      // 验证仍然在登录页面（未跳转）
      const currentUrl = talentMiniPage.page.url();
      expect(currentUrl).toContain('/talent-mini');

      // 验证未存储 token
      const token = await talentMiniPage.getToken();
      expect(token).toBeNull();
    });

    test('登录失败后登录按钮可以重新点击', async ({ talentMiniPage }) => {
      // 导航到登录页面
      await talentMiniPage.goto();

      // 使用错误的凭据尝试登录
      await talentMiniPage.login('12345678901', 'wrongpassword');

      // 等待 API 响应
      await talentMiniPage.page.waitForTimeout(2000);

      // 验证登录按钮仍然可见且可点击
      const loginButton = talentMiniPage.page.getByText('登录').nth(1);
      await expect(loginButton).toBeVisible();
      await expect(loginButton).toBeEnabled();
    });
  });

  test.describe.serial('基本登录成功测试 (AC1)', () => {
    // 使用 Story 12.3 创建的固定测试用户
    const TEST_USER = {
      account: '13800128219',
      password: 'admin123',
      username: 'talent_test_e2e',
    };

    test.afterEach(async ({ talentMiniPage }) => {
      // 清理认证状态
      await talentMiniPage.clearAuth();
    });

    test('应该成功登录人才小程序', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login(TEST_USER.account, TEST_USER.password);

      // 3. 验证登录成功（URL 跳转到主页）
      await talentMiniPage.expectLoginSuccess();
    });

    test('登录成功后应该显示主页或用户信息', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login(TEST_USER.account, TEST_USER.password);

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 验证 URL 跳转到主页
      const currentUrl = talentMiniPage.page.url();
      expect(currentUrl).toMatch(/pages\/index\/index/);
    });

    test('登录成功后 token 应该正确存储到 localStorage (AC1)', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login(TEST_USER.account, TEST_USER.password);

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 验证 token 被正确存储到 localStorage（key: talent_token）
      const token = await talentMiniPage.getToken();
      expect(token).not.toBeNull();
      expect(token?.length).toBeGreaterThan(0);
    });
  });

  test.describe.serial('Token 持久性测试 (AC4)', () => {
    const TEST_USER = {
      account: '13800128219',
      password: 'admin123',
      username: 'talent_test_e2e',
    };

    test.afterEach(async ({ talentMiniPage }) => {
      // 清理认证状态
      await talentMiniPage.clearAuth();
    });

    test('页面刷新后 token 仍然有效', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login(TEST_USER.account, TEST_USER.password);

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 获取登录后的 token
      const tokenBeforeRefresh = await talentMiniPage.getToken();
      expect(tokenBeforeRefresh).not.toBeNull();

      // 5. 刷新页面
      await talentMiniPage.page.reload();

      // 6. 等待页面加载完成
      await talentMiniPage.page.waitForLoadState('domcontentloaded');

      // 7. 验证 token 仍然存在
      const tokenAfterRefresh = await talentMiniPage.getToken();
      expect(tokenAfterRefresh).toBe(tokenBeforeRefresh);
    });

    test('使用已存储 token 可以继续访问', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login(TEST_USER.account, TEST_USER.password);

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 获取 token
      const token = await talentMiniPage.getToken();
      expect(token).not.toBeNull();

      // 5. 重新导航到小程序（模拟关闭后重新打开）
      await talentMiniPage.goto();

      // 6. 验证由于 token 存在，用户保持登录状态
      await talentMiniPage.page.waitForURL(
        url => url.pathname.includes('/pages/index/index') || url.hash.includes('/pages/index/index'),
        { timeout: 10000 }
      ).catch(() => {
        // 如果没有自动跳转，检查当前 URL
        const currentUrl = talentMiniPage.page.url();
        expect(currentUrl).toMatch(/pages\/index\/index/);
      });
    });
  });

  test.describe.serial('退出登录测试 (AC5)', () => {
    const TEST_USER = {
      account: '13800128219',
      password: 'admin123',
      username: 'talent_test_e2e',
    };

    test.afterEach(async ({ talentMiniPage }) => {
      // 清理认证状态
      await talentMiniPage.clearAuth();
    });

    test('应该成功退出登录', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login(TEST_USER.account, TEST_USER.password);

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 退出登录
      await talentMiniPage.gotoMorePage();
      await talentMiniPage.clickLogout();

      // 5. 验证返回到登录页面
      await talentMiniPage.expectToBeOnLoginPage();

      // 6. 验证 URL 返回到登录页面
      const currentUrl = talentMiniPage.page.url();
      expect(currentUrl).toContain('/talent-mini');
      expect(currentUrl).toContain('/pages/login/index');
    });

    test('退出后 token 应该被清除', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login(TEST_USER.account, TEST_USER.password);

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 验证 token 存在
      const tokenBeforeLogout = await talentMiniPage.getToken();
      expect(tokenBeforeLogout).not.toBeNull();

      // 5. 退出登录
      await talentMiniPage.gotoMorePage();
      await talentMiniPage.clickLogout();

      // 6. 等待退出完成
      await talentMiniPage.page.waitForTimeout(1000);

      // 7. 验证 token 已被清除
      const tokenAfterLogout = await talentMiniPage.getToken();
      expect(tokenAfterLogout).toBeNull();
    });

    test('退出后无法访问需要认证的页面', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login(TEST_USER.account, TEST_USER.password);

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 退出登录
      await talentMiniPage.gotoMorePage();
      await talentMiniPage.clickLogout();
      await talentMiniPage.expectToBeOnLoginPage();

      // 5. 尝试直接访问需要认证的页面（主页）
      await talentMiniPage.page.goto('/talent-mini/#/talent-mini/pages/index/index');

      // 6. 验证被重定向回登录页面
      await talentMiniPage.page.waitForLoadState('domcontentloaded');
      const currentUrl = talentMiniPage.page.url();
      expect(currentUrl).toContain('/pages/login/index');

      // 7. 验证登录页面可见
      // 验证仍然在登录页面（未跳转）
    });
  });

  test.describe.serial('测试隔离和清理 (AC6)', () => {
    test('每个测试使用独立的测试用户', async ({ talentMiniPage, browser }) => {
      // 1. 创建唯一的测试用户
      const uniqueId = Date.now();
      const testUsername = `talent_isolated_${uniqueId}`;
      const testPassword = 'Test123!@#';

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        nickname: `隔离测试用户_${uniqueId}`,
        disabilityPersonId: 1,
      });

      // 2. 使用该用户登录小程序
      await talentMiniPage.goto();
      await talentMiniPage.login(testUsername, testPassword);

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 验证 token 存储
      const token = await talentMiniPage.getToken();
      expect(token).not.toBeNull();
    });

    test('测试后清理认证状态', async ({ talentMiniPage }) => {
      // 1. 导航到登录页面
      await talentMiniPage.goto();

      // 2. 使用测试用户登录
      await talentMiniPage.login('13800128219', 'admin123');

      // 3. 验证登录成功
      await talentMiniPage.expectLoginSuccess();

      // 4. 验证 token 存在
      const tokenBeforeClear = await talentMiniPage.getToken();
      expect(tokenBeforeClear).not.toBeNull();

      // 5. 清理认证状态
      await talentMiniPage.clearAuth();

      // 6. 验证 token 已被清除
      const tokenAfterClear = await talentMiniPage.getToken();
      expect(tokenAfterClear).toBeNull();
    });
  });
});
