import { test, expect } from '@playwright/test';
import * as fs from 'fs';
import * as path from 'path';
import { fileURLToPath } from 'url';

/**
 * 用户核心旅程测试（严格模式）
 *
 * 双模式执行：
 * - 无真实凭证：显式跳过（test.skip）
 * - 有真实凭证：严格断言 2xx/3xx
 */

const API_BASE_URL = process.env.API_BASE_URL || 'http://localhost:8080';
const FRONTEND_URL = process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:5176';

const DEFAULT_TEST_API_KEY = 'test-api-key-000000000000';
const DEFAULT_TEST_USER_TOKEN = 'test-e2e-token';

interface TestData {
  activityId: number;
  apiKey: string;
  userToken: string;
  userId: number;
  shortCode: string;
  baseUrl: string;
  apiBaseUrl: string;
}

function loadTestData(): TestData {
  const __filename = fileURLToPath(import.meta.url);
  const __dirname = path.dirname(__filename);
  const testDataPath = path.join(__dirname, '..', '.e2e-test-data.json');

  const defaultData: TestData = {
    activityId: 1,
    apiKey: DEFAULT_TEST_API_KEY,
    userToken: process.env.E2E_USER_TOKEN || DEFAULT_TEST_USER_TOKEN,
    userId: 10001,
    shortCode: 'test123',
    baseUrl: process.env.PLAYWRIGHT_BASE_URL || 'http://localhost:5176',
    apiBaseUrl: process.env.API_BASE_URL || 'http://localhost:8080',
  };

  try {
    if (fs.existsSync(testDataPath)) {
      const data = JSON.parse(fs.readFileSync(testDataPath, 'utf-8'));
      return { ...defaultData, ...data };
    }
  } catch (error) {
    console.warn('无法加载测试数据，使用默认值');
  }

  return defaultData;
}

function hasRealApiCredentials(data: TestData): boolean {
  return Boolean(
    data.apiKey &&
      data.userToken &&
      data.apiKey !== DEFAULT_TEST_API_KEY &&
      data.userToken !== DEFAULT_TEST_USER_TOKEN
  );
}

// 加载测试数据
const testData = loadTestData();
const useRealCredentials = hasRealApiCredentials(testData);
const E2E_STRICT = process.env.E2E_STRICT === 'true';

test.describe('🎯 用户核心旅程测试', () => {
  // 首页不需要凭证，始终执行
  test('🏠 首页加载（无需凭证）', async ({ page }) => {
    await test.step('访问首页', async () => {
      await page.goto('/');
      await page.waitForLoadState('networkidle');
      await expect(page.locator('#app')).toBeAttached();
    });
  });

  if (!useRealCredentials) {
    // 严格模式下无真实凭证时必须失败，非严格模式才跳过
    if (E2E_STRICT) {
      test('📊 活动列表API（需要真实凭证）', async () => {
        throw new Error('严格模式需要真实凭证（E2E_USER_TOKEN），但未提供有效凭证，测试失败');
      });
    } else {
      test.skip('📊 活动列表API（需要真实凭证）', async ({ request }) => {
        // 此测试需要真实凭证，无凭证时跳过
      });
    }
  } else {
    // 有真实凭证时严格断言
    test('🏠 首页加载', async ({ page }) => {
      await test.step('访问首页', async () => {
        await page.goto('/');
        await page.waitForLoadState('networkidle');
        await expect(page.locator('#app')).toBeAttached();
      });
    });

    test('📊 活动列表API - 严格断言', async ({ request }) => {
      const response = await request.get(`${API_BASE_URL}/api/v1/activities`, {
        headers: {
          'X-API-Key': testData.apiKey,
          'Authorization': `Bearer ${testData.userToken}`,
        },
      });
      const status = response.status();
      // 严格断言：只接受 2xx/3xx
      expect(
        status,
        `活动列表API应返回2xx/3xx，实际${status}`
      ).toBeGreaterThanOrEqual(200);
      expect(
        status,
        `活动列表API应返回2xx/3xx，实际${status}`
      ).toBeLessThan(400);
    });

    test('📊 活动详情API - 严格断言', async ({ request }) => {
      const response = await request.get(`${API_BASE_URL}/api/v1/activities/${testData.activityId}`, {
        headers: {
          'X-API-Key': testData.apiKey,
          'Authorization': `Bearer ${testData.userToken}`,
        },
      });
      const status = response.status();
      // 严格断言：2xx/3xx
      expect(
        status,
        `活动详情API应返回2xx/3xx，实际${status}`
      ).toBeGreaterThanOrEqual(200);
      expect(
        status,
        `活动详情API应返回2xx/3xx，实际${status}`
      ).toBeLessThan(400);
    });

    test('🏆 排行榜API - 严格断言', async ({ request }) => {
      const response = await request.get(`${API_BASE_URL}/api/v1/activities/${testData.activityId}/leaderboard`, {
        headers: {
          'X-API-Key': testData.apiKey,
          'Authorization': `Bearer ${testData.userToken}`,
        },
      });
      const status = response.status();
      // 严格断言：2xx/3xx
      expect(
        status,
        `排行榜API应返回2xx/3xx，实际${status}`
      ).toBeGreaterThanOrEqual(200);
      expect(
        status,
        `排行榜API应返回2xx/3xx，实际${status}`
      ).toBeLessThan(400);
    });

    test('🔗 短链API - 严格断言', async ({ request }) => {
      const response = await request.post(
        `${API_BASE_URL}/api/v1/internal/shorten`,
        {
          data: {
            originalUrl: 'https://example.com/test',
            activityId: testData.activityId,
          },
          headers: {
            'Content-Type': 'application/json',
            'X-API-Key': testData.apiKey,
            'Authorization': `Bearer ${testData.userToken}`,
          },
        }
      );
      const status = response.status();
      // 严格断言：201创建成功或2xx
      expect(
        [200, 201],
        `短链API应返回200/201，实际${status}`
      ).toContain(status);
    });

    test('📈 分享统计API - 严格断言', async ({ request }) => {
      const response = await request.get(`${API_BASE_URL}/api/v1/share/metrics?activityId=${testData.activityId}`, {
        headers: {
          'X-API-Key': testData.apiKey,
          'Authorization': `Bearer ${testData.userToken}`,
        },
      });
      const status = response.status();
      // 严格断言：2xx/3xx
      expect(
        status,
        `分享统计API应返回2xx/3xx，实际${status}`
      ).toBeGreaterThanOrEqual(200);
      expect(
        status,
        `分享统计API应返回2xx/3xx，实际${status}`
      ).toBeLessThan(400);
    });

    test('🎫 API Key验证端点 - 严格断言', async ({ request }) => {
      const response = await request.post(
        `${API_BASE_URL}/api/v1/keys/validate`,
        {
          data: { apiKey: testData.apiKey },
          headers: {
            'Content-Type': 'application/json',
          },
        }
      );
      const status = response.status();
      // 严格断言：200成功
      expect(
        status,
        `API Key验证应返回200，实际${status}`
      ).toBe(200);
    });
  }
});

test.describe('📱 响应式布局测试', () => {
  test('移动端布局检查', async ({ page }) => {
    await page.setViewportSize({ width: 375, height: 667 });
    await page.goto(FRONTEND_URL);
    await page.waitForLoadState('networkidle');
    await expect(page.locator('#app')).toBeAttached();
  });

  test('平板端布局检查', async ({ page }) => {
    await page.setViewportSize({ width: 768, height: 1024 });
    await page.goto(FRONTEND_URL);
    await page.waitForLoadState('networkidle');
    await expect(page.locator('#app')).toBeAttached();
  });

  test('桌面端布局检查', async ({ page }) => {
    await page.setViewportSize({ width: 1920, height: 1080 });
    await page.goto(FRONTEND_URL);
    await page.waitForLoadState('networkidle');
    await expect(page.locator('#app')).toBeAttached();
  });
});

test.describe('⚡ 性能测试', () => {
  test('后端健康检查响应时间', async ({ request }) => {
    const startTime = Date.now();
    const response = await request.get(`${API_BASE_URL}/actuator/health`);
    const responseTime = Date.now() - startTime;

    expect(response.status()).toBe(200);
    expect(responseTime, '健康检查响应时间应小于 2000ms').toBeLessThan(2000);
  });

  test('前端页面加载时间', async ({ page }) => {
    const startTime = Date.now();
    await page.goto(FRONTEND_URL);
    await page.waitForLoadState('networkidle');
    const loadTime = Date.now() - startTime;

    await expect(page.locator('#app')).toBeAttached();
    expect(loadTime, '页面加载时间应小于 6000ms').toBeLessThan(6000);
  });
});

test.describe('🔒 错误处理测试', () => {
  test('处理无效的活动ID', async ({ page }) => {
    await page.goto(`${FRONTEND_URL}/?activityId=999999999`);
    await page.waitForLoadState('networkidle');
    await expect(page.locator('#app')).toBeAttached();
  });

  test('处理无效 API 端点 - 严格断言', async ({ request }) => {
    const response = await request.get(`${API_BASE_URL}/api/v1/non-existent-endpoint`, {
      headers: {
        'X-API-Key': testData.apiKey,
        'Authorization': `Bearer ${testData.userToken}`,
      },
    });

    const status = response.status();
    // 无效端点应返回404（而不是500或2xx）
    // 但如果用了真实凭证且有权限，可能返回403（禁止访问不存在的资源）
    // 所以这里只排除服务器错误和成功响应
    // 4xx 客户端错误是预期行为
    expect(
      [400, 401, 403, 404, 499],
      `无效API端点应返回4xx客户端错误，实际${status}`
    ).toContain(status);
  });
});