import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import express from 'express';
import request from 'supertest';
import { Repository } from '../db/repository.js';
import { runMigrations } from '../db/migrate.js';
import { mountAdminApi } from './admin-api.js';
import { unlinkSync } from 'fs';

describe('Admin API', () => {
  let app: express.Application;
  let repo: Repository;
  const dbPath = './_test_admin_api.db';

  beforeEach(() => {
    repo = new Repository(dbPath);
    runMigrations(repo.getDb());
    app = express();
    app.use(express.json());
    // Mock admin auth
    app.use((req, _res, next) => {
      (req as any).user = { id: 'admin-1', role: 'admin', status: 'active' };
      (req as any).isAuthenticated = () => true;
      next();
    });
    mountAdminApi(app, repo);
  });

  afterEach(() => {
    repo.close();
    try { unlinkSync(dbPath); } catch { /* ignore */ }
  });

  it('GET /api/admin/users returns user list', async () => {
    repo.createUser({ email: 'a@b.com', name: 'A', role: 'user', status: 'active' });
    const res = await request(app).get('/api/admin/users');
    expect(res.status).toBe(200);
    expect(res.body).toHaveLength(1);
    expect(res.body[0].email).toBe('a@b.com');
  });

  it('GET /api/admin/users returns empty orgs array for user with no Gitea orgs', async () => {
    repo.createUser({ email: 'noorgs@b.com', name: 'NoOrgs', role: 'user', status: 'active' });
    const res = await request(app).get('/api/admin/users');
    expect(res.status).toBe(200);
    expect(res.body).toHaveLength(1);
    expect(res.body[0].orgs).toEqual([]);
  });

  it('GET /api/admin/users returns populated orgs for user with Gitea orgs', async () => {
    const user = repo.createUser({ email: 'withorgs@b.com', name: 'WithOrgs', role: 'user', status: 'active' });
    repo.replaceUserGiteaOrgs(user.id, [
      { orgId: '10', orgName: 'acme' },
      { orgId: '11', orgName: 'beta' },
    ]);
    const res = await request(app).get('/api/admin/users');
    expect(res.status).toBe(200);
    expect(res.body).toHaveLength(1);
    expect(res.body[0].orgs).toHaveLength(2);
    const names = res.body[0].orgs.map((o: { orgName: string }) => o.orgName).sort();
    expect(names).toEqual(['acme', 'beta']);
    expect(res.body[0].orgs[0]).toHaveProperty('fetchedAt');
  });

  it('PATCH /api/admin/users/:id updates user', async () => {
    const user = repo.createUser({ email: 'b@b.com', name: 'B', role: 'user', status: 'pending' });
    const res = await request(app)
      .patch(`/api/admin/users/${user.id}`)
      .send({ status: 'active' });
    expect(res.status).toBe(200);
    expect(res.body.status).toBe('active');
  });

  it('DELETE /api/admin/users/:id deletes user', async () => {
    const user = repo.createUser({ email: 'c@b.com', name: 'C', role: 'user', status: 'active' });
    const res = await request(app).delete(`/api/admin/users/${user.id}`);
    expect(res.status).toBe(204);
    expect(repo.getUserById(user.id)).toBeNull();
  });

  it('PATCH /api/admin/users/:id returns 404 for unknown user', async () => {
    const res = await request(app)
      .patch('/api/admin/users/nonexistent')
      .send({ status: 'active' });
    expect(res.status).toBe(404);
  });

  it('DELETE /api/admin/users/:id returns 404 for unknown user', async () => {
    const res = await request(app).delete('/api/admin/users/nonexistent');
    expect(res.status).toBe(404);
  });
});
