import { describe, it, expect, vi, beforeEach } from 'vitest';
import { readFileSync } from 'fs';
import { resolve } from 'path';

const ROOT = resolve(__dirname, '../..');

/**
 * Phase 3 Feature Tests
 * Tests for: Seconds-based quota, Admin multi-page layout, Profile page, ECharts integration
 */

// ──────────────────────────────────────────────
// 1. Seconds-based Quota System Verification
// ──────────────────────────────────────────────

describe('Phase 3: Seconds-Based Quota System', () => {
  it('User model should have daily_seconds_limit and monthly_seconds_limit fields', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/accounts/models.py'), 'utf-8');
    expect(src).toContain('daily_seconds_limit');
    expect(src).toContain('monthly_seconds_limit');
    expect(src).not.toContain('daily_limit = models.');  // old field should be gone
    expect(src).not.toContain('monthly_limit = models.'); // old field should be gone
  });

  it('User model default quota should be 600s/day and 6000s/month', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/accounts/models.py'), 'utf-8');
    expect(src).toMatch(/daily_seconds_limit.*default=600/);
    expect(src).toMatch(/monthly_seconds_limit.*default=6000/);
  });

  it('GenerationRecord should have seconds_consumed field', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/models.py'), 'utf-8');
    expect(src).toContain('seconds_consumed');
    expect(src).toMatch(/seconds_consumed\s*=\s*models\.FloatField/);
  });

  it('Video generate view should use seconds-based quota check', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/views.py'), 'utf-8');
    expect(src).toContain('daily_seconds_limit');
    expect(src).toContain('monthly_seconds_limit');
    expect(src).toContain("seconds_consumed");
    // Check that quota enforcement uses Sum of seconds_consumed
    expect(src).toContain("Sum('seconds_consumed')");
  });

  it('Frontend Quota type should use seconds fields', () => {
    const src = readFileSync(resolve(ROOT, 'src/types/index.ts'), 'utf-8');
    expect(src).toContain('daily_seconds_limit: number');
    expect(src).toContain('daily_seconds_used: number');
    expect(src).toContain('monthly_seconds_limit: number');
    expect(src).toContain('monthly_seconds_used: number');
  });

  it('UserInfoBar should display quota in seconds format', () => {
    const src = readFileSync(resolve(ROOT, 'src/components/UserInfoBar.tsx'), 'utf-8');
    // Should show seconds remaining, not calls remaining
    expect(src).toContain('daily_seconds_limit');
    expect(src).toContain('daily_seconds_used');
    expect(src).toMatch(/s\/.*s\(日\)/); // Format: Xs/Xs(日)
  });

  it('Auth store should have quota state with seconds fields', () => {
    const src = readFileSync(resolve(ROOT, 'src/store/auth.ts'), 'utf-8');
    expect(src).toContain('quota: Quota | null');
    expect(src).toContain('fetchUserInfo');
    // After login, should fetch quota info
    expect(src).toContain('get().fetchUserInfo()');
  });
});

// ──────────────────────────────────────────────
// 2. Admin Multi-Page Layout Verification
// ──────────────────────────────────────────────

describe('Phase 3: Admin Multi-Page Layout', () => {
  it('App.tsx should have nested admin routes under /admin', () => {
    const src = readFileSync(resolve(ROOT, 'src/App.tsx'), 'utf-8');
    expect(src).toContain('path="/admin"');
    expect(src).toContain('path="dashboard"');
    expect(src).toContain('path="users"');
    expect(src).toContain('path="records"');
    expect(src).toContain('path="settings"');
    // Should redirect /admin to /admin/dashboard
    expect(src).toContain('Navigate to="/admin/dashboard"');
  });

  it('Admin routes should require admin access (requireAdmin)', () => {
    const src = readFileSync(resolve(ROOT, 'src/App.tsx'), 'utf-8');
    expect(src).toContain('requireAdmin');
  });

  it('AdminLayout should have sidebar with 4 navigation items', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/AdminLayout.tsx'), 'utf-8');
    expect(src).toContain('/admin/dashboard');
    expect(src).toContain('/admin/users');
    expect(src).toContain('/admin/records');
    expect(src).toContain('/admin/settings');
    expect(src).toContain('仪表盘');
    expect(src).toContain('用户管理');
    expect(src).toContain('消费记录');
    expect(src).toContain('系统设置');
  });

  it('AdminLayout should support sidebar collapse', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/AdminLayout.tsx'), 'utf-8');
    expect(src).toContain('collapsed');
    expect(src).toContain('setCollapsed');
  });

  it('AdminLayout should use NavLink for active state highlighting', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/AdminLayout.tsx'), 'utf-8');
    expect(src).toContain('NavLink');
    expect(src).toContain('isActive');
    expect(src).toContain('navItemActive');
  });

  it('AdminLayout should have back-to-home button', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/AdminLayout.tsx'), 'utf-8');
    expect(src).toContain('返回首页');
    expect(src).toContain("navigate('/')");
  });

  it('AdminLayout should render child routes via Outlet', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/AdminLayout.tsx'), 'utf-8');
    expect(src).toContain('Outlet');
  });
});

// ──────────────────────────────────────────────
// 3. Dashboard Page Verification
// ──────────────────────────────────────────────

describe('Phase 3: Dashboard Page', () => {
  it('should use ECharts for charts', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    expect(src).toContain('echarts');
    expect(src).toContain('ReactEChartsCore');
    expect(src).toContain('LineChart');
    expect(src).toContain('BarChart');
  });

  it('should display 4 stat cards (total users, new users, today seconds, month seconds)', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    expect(src).toContain('总用户数');
    expect(src).toContain('今日新增用户');
    expect(src).toContain('今日消费秒数');
    expect(src).toContain('本月消费秒数');
  });

  it('should show trend arrows with color coding', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    // Positive = green (↑), negative = red (↓)
    expect(src).toContain('positive');
    expect(src).toContain('negative');
    expect(src).toMatch(/card\.change\s*>=\s*0/);
  });

  it('should render consumption trend line chart (30 days)', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    expect(src).toContain('消费趋势');
    expect(src).toContain("type: 'line'");
    expect(src).toContain('daily_trend');
  });

  it('should render top users bar chart (horizontal)', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    expect(src).toContain('用户消费排行');
    expect(src).toContain("type: 'bar'");
    expect(src).toContain('top_users');
  });

  it('should have mock data fallback for development', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    expect(src).toContain('generateMockTrend');
    expect(src).toContain('generateMockTopUsers');
  });

  it('should show skeleton loading state', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    expect(src).toContain('skeleton');
    expect(src).toContain('skeletonCard');
    expect(src).toContain('skeletonChart');
  });

  it('should call adminApi.getStats for data', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    expect(src).toContain('adminApi.getStats');
  });
});

// ──────────────────────────────────────────────
// 4. Users Management Page Verification
// ──────────────────────────────────────────────

describe('Phase 3: Users Management Page', () => {
  it('should render user table with correct columns', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/UsersPage.tsx'), 'utf-8');
    expect(src).toContain('用户名');
    expect(src).toContain('邮箱');
    expect(src).toContain('注册时间');
    expect(src).toContain('状态');
    expect(src).toContain('日限额(秒)');
    expect(src).toContain('月限额(秒)');
    expect(src).toContain('今日消费(秒)');
    expect(src).toContain('本月消费(秒)');
  });

  it('should support search and status filter', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/UsersPage.tsx'), 'utf-8');
    expect(src).toContain('搜索用户名/邮箱');
    expect(src).toContain('全部状态');
    expect(src).toContain('statusFilter');
  });

  it('should have quota edit modal', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/UsersPage.tsx'), 'utf-8');
    expect(src).toContain('编辑配额');
    expect(src).toContain('每日秒数限额');
    expect(src).toContain('每月秒数限额');
    expect(src).toContain('handleSaveQuota');
  });

  it('should have user detail drawer', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/UsersPage.tsx'), 'utf-8');
    expect(src).toContain('用户详情');
    expect(src).toContain('drawerOpen');
    expect(src).toContain('detailUser');
    expect(src).toContain('近期消费记录');
  });

  it('should have enable/disable user toggle', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/UsersPage.tsx'), 'utf-8');
    expect(src).toContain('handleToggleStatus');
    expect(src).toContain('updateUserStatus');
  });

  it('should have pagination', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/UsersPage.tsx'), 'utf-8');
    expect(src).toContain('totalPages');
    expect(src).toContain('pagination');
    expect(src).toContain('setPage');
  });
});

// ──────────────────────────────────────────────
// 5. Records Page Verification
// ──────────────────────────────────────────────

describe('Phase 3: Records Page', () => {
  it('should render records table with correct columns', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/RecordsPage.tsx'), 'utf-8');
    expect(src).toContain('时间');
    expect(src).toContain('用户名');
    expect(src).toContain('消费秒数');
    expect(src).toContain('视频描述');
    expect(src).toContain('模式');
    expect(src).toContain('状态');
  });

  it('should support date range filtering', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/RecordsPage.tsx'), 'utf-8');
    expect(src).toContain('startDate');
    expect(src).toContain('endDate');
    expect(src).toContain('type="date"');
  });

  it('should support CSV export', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/RecordsPage.tsx'), 'utf-8');
    expect(src).toContain('导出 CSV');
    expect(src).toContain('handleExportCSV');
    expect(src).toContain('text/csv');
    expect(src).toContain('Blob');
  });

  it('CSV export should escape special characters to prevent injection', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/RecordsPage.tsx'), 'utf-8');
    // Should escape double quotes and formula injection characters
    expect(src).toContain('replace(/"/g');
    expect(src).toMatch(/replace\(.*\[=\+\\\-@\]/);
  });

  it('should support username search', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/RecordsPage.tsx'), 'utf-8');
    expect(src).toContain('按用户名搜索');
    expect(src).toContain('search');
  });
});

// ──────────────────────────────────────────────
// 6. Settings Page Verification
// ──────────────────────────────────────────────

describe('Phase 3: Settings Page', () => {
  it('should have global quota settings form', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/SettingsPage.tsx'), 'utf-8');
    expect(src).toContain('全局默认配额');
    expect(src).toContain('默认每日限额 (秒)');
    expect(src).toContain('默认每月限额 (秒)');
    expect(src).toContain('保存配额设置');
  });

  it('should have announcement management', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/SettingsPage.tsx'), 'utf-8');
    expect(src).toContain('系统公告');
    expect(src).toContain('announcement_enabled');
    expect(src).toContain('announcement');
    expect(src).toContain('保存公告');
  });

  it('should have announcement toggle switch', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/SettingsPage.tsx'), 'utf-8');
    expect(src).toContain('type="checkbox"');
    expect(src).toContain('announcement_enabled');
  });

  it('should call adminApi.getSettings and adminApi.updateSettings', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/SettingsPage.tsx'), 'utf-8');
    expect(src).toContain('adminApi.getSettings');
    expect(src).toContain('adminApi.updateSettings');
  });
});

// ──────────────────────────────────────────────
// 7. Profile Page Verification
// ──────────────────────────────────────────────

describe('Phase 3: Profile Page', () => {
  it('should have consumption overview with gauge chart', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('GaugeChart');
    expect(src).toContain("type: 'gauge'");
    expect(src).toContain('消费概览');
  });

  it('should show daily and monthly quota progress bars', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('今日额度');
    expect(src).toContain('本月额度');
    expect(src).toContain('progressBar');
    expect(src).toContain('progressFill');
  });

  it('should have consumption trend sparkline with 7d/30d toggle', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('消费趋势');
    expect(src).toContain('近7天');
    expect(src).toContain('近30天');
    expect(src).toContain('trendPeriod');
  });

  it('should show warning banner when daily quota > 80%', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('warningBanner');
    expect(src).toContain('dangerBanner');
    expect(src).toMatch(/dailyPercent\s*>=\s*80/);
    expect(src).toMatch(/dailyPercent\s*>=\s*100/);
  });

  it('should have consumption records list with load more', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('消费记录');
    expect(src).toContain('加载更多');
    expect(src).toContain('recordsPage');
  });

  it('should call profileApi for data', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('profileApi.getOverview');
    expect(src).toContain('profileApi.getRecords');
  });

  it('should have back-to-home button', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('返回首页');
    expect(src).toContain("navigate('/')");
  });

  it('should have logout functionality', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('退出');
    expect(src).toContain('handleLogout');
  });
});

// ──────────────────────────────────────────────
// 8. Backend API Routes Verification
// ──────────────────────────────────────────────

describe('Phase 3: Backend API Routes', () => {
  it('should have all Phase 3 URL patterns', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/urls.py'), 'utf-8');
    const requiredPaths = [
      'video/generate',
      'admin/stats',
      'admin/users',
      'admin/records',
      'admin/settings',
      'profile/overview',
      'profile/records',
    ];
    for (const path of requiredPaths) {
      expect(src).toContain(path);
    }
  });

  it('should have user quota and status management endpoints', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/urls.py'), 'utf-8');
    expect(src).toContain('quota');
    expect(src).toContain('status');
  });

  it('admin views should require IsAdminUser permission', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/views.py'), 'utf-8');
    // All admin views should use IsAdminUser
    const adminViews = ['admin_stats_view', 'admin_users_list_view', 'admin_user_detail_view',
      'admin_user_quota_view', 'admin_user_status_view', 'admin_records_view', 'admin_settings_view'];
    for (const view of adminViews) {
      // Find the view function and check it has IsAdminUser
      const viewRegex = new RegExp(`@permission_classes\\(\\[IsAdminUser\\]\\)\\s*\\ndef\\s+${view}`);
      expect(src).toMatch(viewRegex);
    }
  });

  it('profile views should require IsAuthenticated permission', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/views.py'), 'utf-8');
    const profileViews = ['profile_overview_view', 'profile_records_view'];
    for (const view of profileViews) {
      const viewRegex = new RegExp(`@permission_classes\\(\\[IsAuthenticated\\]\\)\\s*\\ndef\\s+${view}`);
      expect(src).toMatch(viewRegex);
    }
  });
});

// ──────────────────────────────────────────────
// 9. QuotaConfig Model Verification
// ──────────────────────────────────────────────

describe('Phase 3: QuotaConfig Model (System Settings)', () => {
  it('should have default quota fields in seconds', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/models.py'), 'utf-8');
    expect(src).toContain('default_daily_seconds_limit');
    expect(src).toContain('default_monthly_seconds_limit');
  });

  it('should have announcement fields', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/models.py'), 'utf-8');
    expect(src).toContain('announcement');
    expect(src).toContain('announcement_enabled');
  });

  it('should enforce singleton pattern (pk=1)', () => {
    const src = readFileSync(resolve(ROOT, 'backend/apps/generation/models.py'), 'utf-8');
    expect(src).toContain('self.pk = 1');
  });
});

// ──────────────────────────────────────────────
// 10. ProtectedRoute Admin Guard
// ──────────────────────────────────────────────

describe('Phase 3: ProtectedRoute Admin Guard', () => {
  it('should redirect non-admin users away from admin routes', () => {
    const src = readFileSync(resolve(ROOT, 'src/components/ProtectedRoute.tsx'), 'utf-8');
    expect(src).toContain('requireAdmin');
    expect(src).toContain('is_staff');
    // Non-admin should be redirected to /
    expect(src).toContain('Navigate to="/"');
  });
});

// ──────────────────────────────────────────────
// 11. UserInfoBar Phase 3 Features
// ──────────────────────────────────────────────

describe('Phase 3: UserInfoBar Navigation', () => {
  it('should have profile link', () => {
    const src = readFileSync(resolve(ROOT, 'src/components/UserInfoBar.tsx'), 'utf-8');
    expect(src).toContain('个人中心');
    expect(src).toContain("'/profile'");
  });

  it('should show admin link only for staff users', () => {
    const src = readFileSync(resolve(ROOT, 'src/components/UserInfoBar.tsx'), 'utf-8');
    expect(src).toContain('is_staff');
    expect(src).toContain('管理后台');
    expect(src).toContain("'/admin/dashboard'");
  });
});

// ──────────────────────────────────────────────
// 12. ECharts Integration
// ──────────────────────────────────────────────

describe('Phase 3: ECharts Integration', () => {
  it('package.json should include echarts dependencies', () => {
    const pkg = JSON.parse(readFileSync(resolve(ROOT, 'package.json'), 'utf-8'));
    expect(pkg.dependencies.echarts).toBeDefined();
    expect(pkg.dependencies['echarts-for-react']).toBeDefined();
  });

  it('DashboardPage should use ECharts components', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/DashboardPage.tsx'), 'utf-8');
    expect(src).toContain('echarts/core');
    expect(src).toContain('echarts/charts');
    expect(src).toContain('CanvasRenderer');
    expect(src).toContain('TooltipComponent');
    expect(src).toContain('DataZoomComponent');
  });

  it('ProfilePage should use ECharts for gauge and sparkline', () => {
    const src = readFileSync(resolve(ROOT, 'src/pages/ProfilePage.tsx'), 'utf-8');
    expect(src).toContain('GaugeChart');
    expect(src).toContain('LineChart');
    expect(src).toContain('CanvasRenderer');
  });
});

// ──────────────────────────────────────────────
// 13. Frontend Route Configuration
// ──────────────────────────────────────────────

describe('Phase 3: Route Configuration', () => {
  it('should have /profile route', () => {
    const src = readFileSync(resolve(ROOT, 'src/App.tsx'), 'utf-8');
    expect(src).toContain('path="/profile"');
    expect(src).toContain('ProfilePage');
  });

  it('/profile should be protected', () => {
    const src = readFileSync(resolve(ROOT, 'src/App.tsx'), 'utf-8');
    // ProfilePage should be wrapped in ProtectedRoute
    const profileSection = src.slice(
      src.indexOf('path="/profile"'),
      src.indexOf('path="/admin"')
    );
    expect(profileSection).toContain('ProtectedRoute');
  });

  it('/admin should redirect to /admin/dashboard', () => {
    const src = readFileSync(resolve(ROOT, 'src/App.tsx'), 'utf-8');
    expect(src).toContain('Navigate to="/admin/dashboard" replace');
  });

  it('unknown routes should redirect to /', () => {
    const src = readFileSync(resolve(ROOT, 'src/App.tsx'), 'utf-8');
    expect(src).toContain('path="*"');
    expect(src).toContain('Navigate to="/"');
  });
});
