import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import path from 'node:path';
import test from 'node:test';
import Fastify from 'fastify';
import { registerChatRoutes, resolvePromptFollowupMode, resolveStaticContentType } from './chat.js';

const repoRoot = path.resolve(process.cwd(), '../../..');

async function removeSessionUploads(sessionId: string) {
  await fs.rm(path.join(repoRoot, 'public', '.codex_chat', sessionId), {
    recursive: true,
    force: true,
  });
}

test('resolveStaticContentType returns html content type for chat resource html files', () => {
  assert.equal(resolveStaticContentType('/tmp/sample.html'), 'text/html; charset=utf-8');
  assert.equal(resolveStaticContentType('/tmp/sample.htm'), 'text/html; charset=utf-8');
});

test('resolveStaticContentType keeps plain text content type for code resources', () => {
  assert.equal(resolveStaticContentType('/tmp/sample.ts'), 'text/plain; charset=utf-8');
  assert.equal(resolveStaticContentType('/tmp/sample.diff'), 'text/plain; charset=utf-8');
});

test('resolvePromptFollowupMode defaults to queue and preserves direct mode', () => {
  assert.equal(resolvePromptFollowupMode(undefined), 'queue');
  assert.equal(resolvePromptFollowupMode(null), 'queue');
  assert.equal(resolvePromptFollowupMode('queue'), 'queue');
  assert.equal(resolvePromptFollowupMode('direct'), 'direct');
});

test('chat attachments accept binary octet-stream uploads without base64 expansion', async () => {
  const app = Fastify();
  await registerChatRoutes(app);
  const sessionId = `binary-upload-${Date.now()}`;
  const payload = Buffer.alloc(829_627, 1);

  try {
    const response = await app.inject({
      method: 'POST',
      url: '/api/chat/attachments',
      headers: {
        'content-type': 'application/octet-stream',
        'x-chat-attachment-session-id': sessionId,
        'x-chat-attachment-file-name': encodeURIComponent('image.png'),
        'x-chat-attachment-mime-type': encodeURIComponent('image/png'),
      },
      payload,
    });

    assert.equal(response.statusCode, 200);
    const body = response.json() as { ok: boolean; item: { path: string; size: number; mimeType: string } };
    assert.equal(body.ok, true);
    assert.equal(body.item.size, payload.byteLength);
    assert.equal(body.item.mimeType, 'image/png');
    assert.match(body.item.path, new RegExp(`^public/\\.codex_chat/${sessionId}/resource/uploads/.+image\\.png$`));
  } finally {
    await removeSessionUploads(sessionId);
    await app.close();
  }
});

test('chat attachments keep legacy JSON base64 uploads working', async () => {
  const app = Fastify();
  await registerChatRoutes(app);
  const sessionId = `json-upload-${Date.now()}`;

  try {
    const response = await app.inject({
      method: 'POST',
      url: '/api/chat/attachments',
      headers: {
        'content-type': 'application/json',
      },
      payload: JSON.stringify({
        sessionId,
        fileName: 'note.txt',
        mimeType: 'text/plain',
        contentBase64: Buffer.from('hello', 'utf8').toString('base64'),
      }),
    });

    assert.equal(response.statusCode, 200);
    const body = response.json() as { ok: boolean; item: { size: number; mimeType: string; name: string } };
    assert.equal(body.ok, true);
    assert.equal(body.item.size, 5);
    assert.equal(body.item.mimeType, 'text/plain');
    assert.equal(body.item.name, 'note.txt');
  } finally {
    await removeSessionUploads(sessionId);
    await app.close();
  }
});
