import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import express from 'express';
import request from 'supertest';
import { mkdtempSync, rmSync } from 'fs';
import { join } from 'path';
import { tmpdir } from 'os';
import { createUserFolderApi } from './user-folder-api.js';

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

function makeApp(userId: string, userFolderRoot: string): express.Application {
  const app = express();
  app.use((req, _res, next) => {
    (req as any).user = { id: userId, role: 'user' };
    next();
  });
  app.use('/api/users/me', createUserFolderApi({ userFolderRoot }));
  return app;
}

// ---------------------------------------------------------------------------
// Tests
// ---------------------------------------------------------------------------

describe('User Folder API — AGENTS.md routes', () => {
  let tmpRoot: string;
  let app: express.Application;
  const USER_A = 'user-a';

  beforeEach(() => {
    tmpRoot = mkdtempSync(join(tmpdir(), 'agents-md-test-'));
    app = makeApp(USER_A, tmpRoot);
  });

  afterEach(() => {
    rmSync(tmpRoot, { recursive: true, force: true });
  });

  // ── GET /agents-md ────────────────────────────────────────────────────────

  it('GET /agents-md returns exists=false when file is missing', async () => {
    const res = await request(app).get('/api/users/me/agents-md');
    expect(res.status).toBe(200);
    expect(res.body).toEqual({ exists: false, content: '' });
  });

  // ── PUT /agents-md ────────────────────────────────────────────────────────

  it('PUT /agents-md writes content; subsequent GET reflects it', async () => {
    const text = '# My Instructions\n\nAlways be concise.\n';

    const putRes = await request(app)
      .put('/api/users/me/agents-md')
      .set('Content-Type', 'text/plain')
      .send(text);
    expect(putRes.status).toBe(200);
    expect(putRes.body.ok).toBe(true);
    expect(typeof putRes.body.bytes).toBe('number');

    const getRes = await request(app).get('/api/users/me/agents-md');
    expect(getRes.status).toBe(200);
    expect(getRes.body.exists).toBe(true);
    expect(getRes.body.content).toBe(text);
  });

  it('PUT /agents-md with oversized body returns 413', async () => {
    // 64 KB + 1 byte — exceeds USER_AGENTS_MAX_BYTES
    const oversized = 'x'.repeat(64 * 1024 + 1);

    const res = await request(app)
      .put('/api/users/me/agents-md')
      .set('Content-Type', 'text/plain')
      .send(oversized);
    expect(res.status).toBe(413);
    expect(res.body.error).toMatch(/exceeds/);
  });

  // ── DELETE /agents-md ─────────────────────────────────────────────────────

  it('DELETE /agents-md removes the file', async () => {
    // First write something
    await request(app)
      .put('/api/users/me/agents-md')
      .set('Content-Type', 'text/plain')
      .send('# Hello\n');

    // Confirm it exists
    const beforeGet = await request(app).get('/api/users/me/agents-md');
    expect(beforeGet.body.exists).toBe(true);

    // Delete it
    const delRes = await request(app).delete('/api/users/me/agents-md');
    expect(delRes.status).toBe(200);
    expect(delRes.body.ok).toBe(true);
    expect(delRes.body.existed).toBe(true);

    // Confirm it's gone
    const afterGet = await request(app).get('/api/users/me/agents-md');
    expect(afterGet.body.exists).toBe(false);
  });

  it('DELETE /agents-md when file does not exist returns ok=true, existed=false', async () => {
    const res = await request(app).delete('/api/users/me/agents-md');
    expect(res.status).toBe(200);
    expect(res.body.ok).toBe(true);
    expect(res.body.existed).toBe(false);
  });
});
