import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';

// Mock the auth store
const mockAuthState = {
  user: null as any,
  isAuthenticated: false,
  isLoading: false,
  quota: null as any,
  logout: vi.fn(),
  initialize: vi.fn(),
};

vi.mock('../../src/store/auth', () => ({
  useAuthStore: (selector: (s: any) => any) => selector(mockAuthState),
}));

describe('ProtectedRoute', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockAuthState.user = null;
    mockAuthState.isAuthenticated = false;
    mockAuthState.isLoading = false;
    mockAuthState.quota = null;
  });

  it('should show loading when isLoading is true', async () => {
    mockAuthState.isLoading = true;
    const { ProtectedRoute } = await import('../../src/components/ProtectedRoute');

    render(
      <MemoryRouter>
        <ProtectedRoute><div>Protected Content</div></ProtectedRoute>
      </MemoryRouter>
    );

    expect(screen.getByText('加载中...')).toBeInTheDocument();
    expect(screen.queryByText('Protected Content')).not.toBeInTheDocument();
  });

  it('should redirect to /login when not authenticated', async () => {
    mockAuthState.isAuthenticated = false;
    mockAuthState.isLoading = false;
    const { ProtectedRoute } = await import('../../src/components/ProtectedRoute');

    const { container } = render(
      <MemoryRouter initialEntries={['/']}>
        <ProtectedRoute><div>Protected Content</div></ProtectedRoute>
      </MemoryRouter>
    );

    expect(screen.queryByText('Protected Content')).not.toBeInTheDocument();
  });

  it('should render children when authenticated', async () => {
    mockAuthState.isAuthenticated = true;
    mockAuthState.isLoading = false;
    mockAuthState.user = { id: 1, username: 'test', email: 'e', is_staff: false };
    const { ProtectedRoute } = await import('../../src/components/ProtectedRoute');

    render(
      <MemoryRouter>
        <ProtectedRoute><div>Protected Content</div></ProtectedRoute>
      </MemoryRouter>
    );

    expect(screen.getByText('Protected Content')).toBeInTheDocument();
  });

  it('should redirect non-admin from admin routes', async () => {
    mockAuthState.isAuthenticated = true;
    mockAuthState.isLoading = false;
    mockAuthState.user = { id: 1, username: 'test', email: 'e', is_staff: false };
    const { ProtectedRoute } = await import('../../src/components/ProtectedRoute');

    render(
      <MemoryRouter initialEntries={['/admin/dashboard']}>
        <ProtectedRoute requireAdmin><div>Admin Content</div></ProtectedRoute>
      </MemoryRouter>
    );

    expect(screen.queryByText('Admin Content')).not.toBeInTheDocument();
  });

  it('should render admin content for staff users', async () => {
    mockAuthState.isAuthenticated = true;
    mockAuthState.isLoading = false;
    mockAuthState.user = { id: 1, username: 'admin', email: 'e', is_staff: true };
    const { ProtectedRoute } = await import('../../src/components/ProtectedRoute');

    render(
      <MemoryRouter>
        <ProtectedRoute requireAdmin><div>Admin Content</div></ProtectedRoute>
      </MemoryRouter>
    );

    expect(screen.getByText('Admin Content')).toBeInTheDocument();
  });
});

describe('UserInfoBar', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    mockAuthState.user = null;
    mockAuthState.isAuthenticated = false;
    mockAuthState.isLoading = false;
    mockAuthState.quota = null;
    mockAuthState.logout = vi.fn();
  });

  it('should render nothing when user is null', async () => {
    mockAuthState.user = null;
    const { UserInfoBar } = await import('../../src/components/UserInfoBar');

    const { container } = render(
      <MemoryRouter>
        <UserInfoBar />
      </MemoryRouter>
    );

    expect(container.children.length).toBe(0);
  });

  it('should display username and avatar', async () => {
    mockAuthState.user = { id: 1, username: 'johndoe', email: 'j@t.com', is_staff: false };
    const { UserInfoBar } = await import('../../src/components/UserInfoBar');

    render(
      <MemoryRouter>
        <UserInfoBar />
      </MemoryRouter>
    );

    expect(screen.getByText('johndoe')).toBeInTheDocument();
    expect(screen.getByText('J')).toBeInTheDocument(); // avatar letter
  });

  it('should display quota information in seconds (Phase 3)', async () => {
    mockAuthState.user = { id: 1, username: 'test', email: 'e', is_staff: false };
    mockAuthState.quota = { daily_seconds_limit: 600, daily_seconds_used: 100, monthly_seconds_limit: 6000, monthly_seconds_used: 1000 };
    const { UserInfoBar } = await import('../../src/components/UserInfoBar');

    render(
      <MemoryRouter>
        <UserInfoBar />
      </MemoryRouter>
    );

    // Phase 3: quota display shows seconds format: "剩余: Xs/Xs(日)"
    expect(screen.getByText(/剩余/)).toBeInTheDocument();
    expect(screen.getByText(/500s\/600s/)).toBeInTheDocument();
  });

  it('should show admin button for staff users', async () => {
    mockAuthState.user = { id: 1, username: 'admin', email: 'e', is_staff: true };
    const { UserInfoBar } = await import('../../src/components/UserInfoBar');

    render(
      <MemoryRouter>
        <UserInfoBar />
      </MemoryRouter>
    );

    expect(screen.getByText('管理后台')).toBeInTheDocument();
  });

  it('should NOT show admin button for non-staff users', async () => {
    mockAuthState.user = { id: 1, username: 'regular', email: 'e', is_staff: false };
    const { UserInfoBar } = await import('../../src/components/UserInfoBar');

    render(
      <MemoryRouter>
        <UserInfoBar />
      </MemoryRouter>
    );

    expect(screen.queryByText('管理后台')).not.toBeInTheDocument();
  });

  it('should show logout button', async () => {
    mockAuthState.user = { id: 1, username: 'test', email: 'e', is_staff: false };
    const { UserInfoBar } = await import('../../src/components/UserInfoBar');

    render(
      <MemoryRouter>
        <UserInfoBar />
      </MemoryRouter>
    );

    expect(screen.getByText('退出')).toBeInTheDocument();
  });
});

describe('Phase 2 Type Definitions', () => {
  it('should have User interface with required fields', async () => {
    const types = await import('../../src/types/index');
    // Type verification through instantiation
    const user: typeof types extends { User: infer U } ? never : any = {
      id: 1, username: 'test', email: 'test@test.com', is_staff: false,
    };
    expect(user).toBeDefined();
  });

  it('should have Quota interface with seconds-based fields (Phase 3)', async () => {
    const quota = {
      daily_seconds_limit: 600,
      daily_seconds_used: 100,
      monthly_seconds_limit: 6000,
      monthly_seconds_used: 1000,
    };
    expect(quota.daily_seconds_limit).toBe(600);
    expect(quota.monthly_seconds_limit).toBe(6000);
  });

  it('should have AuthTokens interface', async () => {
    const tokens = { access: 'test', refresh: 'test' };
    expect(tokens.access).toBeDefined();
    expect(tokens.refresh).toBeDefined();
  });

  it('should have AdminStats interface with seconds fields (Phase 3)', async () => {
    const stats = {
      total_users: 100,
      new_users_today: 5,
      seconds_consumed_today: 4560,
      seconds_consumed_this_month: 89010,
      today_change_percent: -5.0,
      month_change_percent: 8.0,
      daily_trend: [{ date: '2026-03-01', seconds: 1200 }],
      top_users: [{ user_id: 1, username: 'alice', seconds_consumed: 2340 }],
    };
    expect(stats.total_users).toBe(100);
    expect(stats.daily_trend).toHaveLength(1);
    expect(stats.daily_trend[0].seconds).toBe(1200);
    expect(stats.top_users[0].seconds_consumed).toBe(2340);
  });

  it('should have AdminUser interface with seconds-based quota (Phase 3)', async () => {
    const user = {
      id: 1,
      username: 'test',
      email: 'test@test.com',
      is_active: true,
      date_joined: '2026-03-01',
      daily_seconds_limit: 600,
      monthly_seconds_limit: 6000,
      seconds_today: 120,
      seconds_this_month: 3500,
    };
    expect(user.daily_seconds_limit).toBe(600);
    expect(user.monthly_seconds_limit).toBe(6000);
  });

  it('should have ProfileOverview interface (Phase 3)', async () => {
    const overview = {
      daily_seconds_limit: 600,
      daily_seconds_used: 120,
      monthly_seconds_limit: 6000,
      monthly_seconds_used: 3500,
      total_seconds_used: 15000,
      daily_trend: [{ date: '2026-03-01', seconds: 45 }],
    };
    expect(overview.daily_seconds_limit).toBe(600);
    expect(overview.daily_trend).toHaveLength(1);
  });

  it('should have SystemSettings interface (Phase 3)', async () => {
    const settings = {
      default_daily_seconds_limit: 600,
      default_monthly_seconds_limit: 6000,
      announcement: 'Test announcement',
      announcement_enabled: true,
    };
    expect(settings.default_daily_seconds_limit).toBe(600);
    expect(settings.announcement_enabled).toBe(true);
  });

  it('UploadedFile type should not include audio', async () => {
    // Verify audio type was removed from UploadedFile (fix from previous sessions)
    const { readFileSync } = await import('fs');
    const typesSrc = readFileSync(
      '/Users/maidong/Desktop/zyc/研究openclaw/视频生成平台/jimeng-clone/src/types/index.ts',
      'utf-8'
    );
    // UploadedFile.type should only be 'image' | 'video'
    const uploadedFileMatch = typesSrc.match(/interface UploadedFile[\s\S]*?type:\s*(.+?);/);
    expect(uploadedFileMatch).toBeTruthy();
    expect(uploadedFileMatch![1]).not.toContain('audio');
  });
});
