import { test, expect } from '../../utils/test-setup';
import { AdminLoginPage } from '../../pages/admin/login.page';
import { UserManagementPage } from '../../pages/admin/user-management.page';
import { UserType } from '@d8d/shared-types';

/**
 * 企业小程序登录 E2E 测试
 *
 * 测试企业用户通过小程序登录的功能，验证：
 * - 登录失败场景
 * - 表单验证
 * - 登录成功场景（使用独立 context 创建测试用户）
 * - Token 持久性
 * - 退出登录
 *
 * @see {@link ../pages/mini/enterprise-mini.page.ts} EnterpriseMiniPage
 */

/**
 * 创建测试用户的辅助函数
 *
 * 在独立的 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;
  phone?: string;
  email?: string;
  userType?: UserType;
  companyName?: string;
}): Promise<{ username: string; password: string }> {
  // 创建独立的 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();

    // 创建测试用户（使用 EMPLOYER 类型，企业用户）
    const result = await userManagementPage.createUser({
      username: userData.username,
      password: userData.password,
      nickname: userData.nickname || '测试企业用户',
      phone: userData.phone,
      email: userData.email,
      userType: userData.userType || UserType.EMPLOYER,
    }, userData.companyName || '默认公司');

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

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

test.describe('企业小程序登录功能', () => {
  test.describe('表单验证测试 (AC3)', () => {
    test('手机号为空时应该显示错误提示', async ({ enterpriseMiniPage }) => {
      // 导航到登录页面
      await enterpriseMiniPage.goto();

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

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

      // 验证登录页面容器仍然可见
      await expect(enterpriseMiniPage.loginPage).toBeVisible();
    });

    test('密码为空时应该显示错误提示', async ({ enterpriseMiniPage }) => {
      // 导航到登录页面
      await enterpriseMiniPage.goto();

      // 只填写手机号，不填写密码
      await enterpriseMiniPage.fillPhone('13800138000');

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

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

      // 验证登录页面容器仍然可见
      await expect(enterpriseMiniPage.loginPage).toBeVisible();
    });

    test('表单验证错误提示应该清晰可见', async ({ enterpriseMiniPage }) => {
      // 导航到登录页面
      await enterpriseMiniPage.goto();

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

      // 验证仍在登录页面
      expect(enterpriseMiniPage.page.url()).toContain('/mini');

      // 验证登录页面容器仍然可见
      await expect(enterpriseMiniPage.loginPage).toBeVisible();
    });
  });

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

      // 使用不存在的用户名尝试登录（使用有效的手机号格式）
      const fakeUsername = `199${Date.now().toString().slice(-8)}`; // 11位数字，符合手机号格式
      await enterpriseMiniPage.login(fakeUsername, 'password123');

      // 验证显示错误提示
      await enterpriseMiniPage.expectLoginError('用户名或密码错误');

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

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

      // 使用不存在的用户尝试登录（使用有效的手机号格式）
      await enterpriseMiniPage.login('19912345678', 'wrongpassword');

      // 验证显示错误提示
      await enterpriseMiniPage.expectLoginError('用户名或密码错误');

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

    test('错误提示内容应该正确', async ({ enterpriseMiniPage }) => {
      // 导航到登录页面
      await enterpriseMiniPage.goto();

      // 使用错误的凭据尝试登录（使用有效的手机号格式）
      await enterpriseMiniPage.login('19987654321', 'wrongpassword');

      // 验证错误提示包含"用户名或密码错误"或类似内容
      await enterpriseMiniPage.expectLoginError();
    });
  });

  test.describe.serial('基本登录成功测试 (AC1)', () => {
    test('应该成功登录企业小程序', async ({ enterpriseMiniPage, browser }) => {
      // 1. 创建测试用户（使用独立 context）
      const testUsername = `mini_test_${Date.now()}`;
      const testPassword = 'Test123!@#';
      const testPhone = `138${Date.now().toString().slice(-8)}`;

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        phone: testPhone,
        nickname: '小程序测试用户',
        userType: UserType.EMPLOYER,
      });

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

      // 3. 验证登录成功（URL 跳转到 dashboard 或显示用户信息）
      await enterpriseMiniPage.expectLoginSuccess();
    });

    test('登录成功后应该显示用户信息', async ({ enterpriseMiniPage, browser }) => {
      // 1. 创建测试用户
      const testUsername = `mini_info_${Date.now()}`;
      const testPassword = 'Test123!@#';
      const testPhone = `139${Date.now().toString().slice(-8)}`;

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        phone: testPhone,
        nickname: '小程序信息测试',
        userType: UserType.EMPLOYER,
      });

      // 2. 登录小程序
      await enterpriseMiniPage.goto();
      await enterpriseMiniPage.login(testPhone, testPassword);

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

      // 4. 验证用户信息显示（检查 userInfo 元素或 dashboard 可见）
      const currentUrl = enterpriseMiniPage.page.url();
      expect(currentUrl).toMatch(/dashboard|pages/);
    });

    test('登录成功后 token 应该正确存储', async ({ enterpriseMiniPage, browser }) => {
      // 1. 创建测试用户
      const testUsername = `mini_token_${Date.now()}`;
      const testPassword = 'Test123!@#';
      const testPhone = `137${Date.now().toString().slice(-8)}`;

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        phone: testPhone,
        nickname: '小程序 Token 测试',
        userType: UserType.EMPLOYER,
      });

      // 2. 登录小程序
      await enterpriseMiniPage.goto();
      await enterpriseMiniPage.login(testPhone, testPassword);

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

      // 4. 验证 token 被正确存储
      const token = await enterpriseMiniPage.getToken();
      expect(token).not.toBeNull();
      expect(token?.length).toBeGreaterThan(0);
    });
  });

  test.describe.serial('Token 持久性测试 (AC4)', () => {
    test('页面刷新后 token 仍然有效', async ({ enterpriseMiniPage, browser }) => {
      // 1. 创建测试用户
      const testUsername = `mini_refresh_${Date.now()}`;
      const testPassword = 'Test123!@#';
      const testPhone = `136${Date.now().toString().slice(-8)}`;

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        phone: testPhone,
        nickname: '小程序刷新测试',
        userType: UserType.EMPLOYER,
      });

      // 2. 登录小程序
      await enterpriseMiniPage.goto();
      await enterpriseMiniPage.login(testPhone, testPassword);
      await enterpriseMiniPage.expectLoginSuccess();

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

      // 4. 刷新页面
      await enterpriseMiniPage.page.reload();

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

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

    test('使用已存储 token 可以继续访问', async ({ enterpriseMiniPage, browser }) => {
      // 1. 创建测试用户
      const testUsername = `mini_persist_${Date.now()}`;
      const testPassword = 'Test123!@#';
      const testPhone = `135${Date.now().toString().slice(-8)}`;

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        phone: testPhone,
        nickname: '小程序持久化测试',
        userType: UserType.EMPLOYER,
      });

      // 2. 登录小程序
      await enterpriseMiniPage.goto();
      await enterpriseMiniPage.login(testPhone, testPassword);
      await enterpriseMiniPage.expectLoginSuccess();

      // 3. 获取 token
      const token = await enterpriseMiniPage.getToken();
      expect(token).not.toBeNull();

      // 4. 重新导航到登录页面（模拟关闭后重新打开）
      await enterpriseMiniPage.goto();

      // 5. 验证由于 token 存在，页面自动跳转到 dashboard
      await enterpriseMiniPage.page.waitForURL(
        url => url.pathname.includes('/dashboard') || url.pathname.includes('/pages'),
        { timeout: 10000 }
      ).catch(() => {
        // 如果没有自动跳转，检查当前 URL
        const currentUrl = enterpriseMiniPage.page.url();
        expect(currentUrl).toMatch(/dashboard|pages/);
      });
    });
  });

  test.describe.serial('退出登录测试 (AC5)', () => {
    test('应该成功退出登录', async ({ enterpriseMiniPage, browser }) => {
      // 1. 创建测试用户
      const testUsername = `mini_logout_${Date.now()}`;
      const testPassword = 'Test123!@#';
      const testPhone = `134${Date.now().toString().slice(-8)}`;

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        phone: testPhone,
        nickname: '小程序退出测试',
        userType: UserType.EMPLOYER,
      });

      // 2. 登录小程序
      await enterpriseMiniPage.goto();
      await enterpriseMiniPage.login(testPhone, testPassword);
      await enterpriseMiniPage.expectLoginSuccess();

      // 3. 退出登录
      await enterpriseMiniPage.logout();

      // 4. 验证返回到登录页面
      await enterpriseMiniPage.expectLoggedOut();

      // 5. 验证 URL 返回到登录页面
      const currentUrl = enterpriseMiniPage.page.url();
      expect(currentUrl).toContain('/mini');
    });

    test('退出后 token 应该被清除', async ({ enterpriseMiniPage, browser }) => {
      // 1. 创建测试用户
      const testUsername = `mini_token_clear_${Date.now()}`;
      const testPassword = 'Test123!@#';
      const testPhone = `133${Date.now().toString().slice(-8)}`;

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        phone: testPhone,
        nickname: '小程序 Token 清除测试',
        userType: UserType.EMPLOYER,
      });

      // 2. 登录小程序
      await enterpriseMiniPage.goto();
      await enterpriseMiniPage.login(testPhone, testPassword);
      await enterpriseMiniPage.expectLoginSuccess();

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

      // 4. 退出登录
      await enterpriseMiniPage.logout();
      await enterpriseMiniPage.expectLoggedOut();

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

    test('退出后无法访问需要认证的页面', async ({ enterpriseMiniPage, browser }) => {
      // 1. 创建测试用户
      const testUsername = `mini_auth_${Date.now()}`;
      const testPassword = 'Test123!@#';
      const testPhone = `132${Date.now().toString().slice(-8)}`;

      await createTestUser(browser, {
        username: testUsername,
        password: testPassword,
        phone: testPhone,
        nickname: '小程序认证测试',
        userType: UserType.EMPLOYER,
      });

      // 2. 登录小程序
      await enterpriseMiniPage.goto();
      await enterpriseMiniPage.login(testPhone, testPassword);
      await enterpriseMiniPage.expectLoginSuccess();

      // 3. 退出登录
      await enterpriseMiniPage.logout();
      await enterpriseMiniPage.expectLoggedOut();

      // 4. 尝试直接访问需要认证的页面（dashboard）
      await enterpriseMiniPage.page.goto('/mini/dashboard');

      // 5. 验证被重定向回登录页面
      await enterpriseMiniPage.page.waitForLoadState('domcontentloaded');
      const currentUrl = enterpriseMiniPage.page.url();
      expect(currentUrl).toContain('/mini');

      // 6. 验证登录页面可见
      await expect(enterpriseMiniPage.loginPage).toBeVisible();
    });
  });
});
