const request = require('supertest');
const { app } = require('../../backend/server');
const { cleanDb, getAuthHeader, seedSession } = require('../helpers/test-utils');
const { computeNotesPreview } = require('../../backend/utils/notes-preview');

describe('computeNotesPreview', () => {
  test('returns has_notes false and null preview for null input', () => {
    const result = computeNotesPreview(null);
    expect(result).toEqual({ has_notes: false, notes_preview: null });
  });

  test('returns has_notes false and null preview for empty string', () => {
    const result = computeNotesPreview('');
    expect(result).toEqual({ has_notes: false, notes_preview: null });
  });

  test('returns first paragraph as preview', () => {
    const notes = 'First paragraph here.\n\nSecond paragraph here.';
    const result = computeNotesPreview(notes);
    expect(result.has_notes).toBe(true);
    expect(result.notes_preview).toBe('First paragraph here.');
  });

  test('strips markdown bold formatting', () => {
    const notes = '**Bold text** and more';
    const result = computeNotesPreview(notes);
    expect(result.notes_preview).toBe('Bold text and more');
  });

  test('strips markdown italic formatting', () => {
    const notes = '*Italic text* and _also italic_';
    const result = computeNotesPreview(notes);
    expect(result.notes_preview).toBe('Italic text and also italic');
  });

  test('strips markdown links', () => {
    const notes = 'Check [this link](http://example.com) out';
    const result = computeNotesPreview(notes);
    expect(result.notes_preview).toBe('Check this link out');
  });

  test('strips markdown headers', () => {
    const notes = '## Header text';
    const result = computeNotesPreview(notes);
    expect(result.notes_preview).toBe('Header text');
  });

  test('strips markdown list markers', () => {
    const notes = '- Item one\n- Item two';
    const result = computeNotesPreview(notes);
    expect(result.notes_preview).toBe('Item one Item two');
  });

  test('truncates to 150 characters with ellipsis', () => {
    const notes = 'A'.repeat(200);
    const result = computeNotesPreview(notes);
    expect(result.notes_preview).toHaveLength(153); // 150 + '...'
    expect(result.notes_preview.endsWith('...')).toBe(true);
  });

  test('does not truncate text at or under 150 characters', () => {
    const notes = 'A'.repeat(150);
    const result = computeNotesPreview(notes);
    expect(result.notes_preview).toHaveLength(150);
    expect(result.notes_preview).not.toContain('...');
  });
});

describe('GET /api/sessions list', () => {
  beforeEach(() => {
    cleanDb();
  });

  test('includes has_notes and notes_preview in list response', async () => {
    seedSession({ notes: '**Bold** first paragraph\n\nSecond paragraph' });
    seedSession({ notes: null });

    const res = await request(app).get('/api/sessions');

    expect(res.status).toBe(200);
    expect(res.body).toHaveLength(2);

    const withNotes = res.body.find(s => s.has_notes === true);
    const withoutNotes = res.body.find(s => s.has_notes === false);

    expect(withNotes.notes_preview).toBe('Bold first paragraph');
    expect(withNotes).not.toHaveProperty('notes');

    expect(withoutNotes.notes_preview).toBeNull();
    expect(withoutNotes).not.toHaveProperty('notes');
  });

  test('list response preserves existing fields', async () => {
    seedSession({ is_active: 1, notes: 'Test' });

    const res = await request(app).get('/api/sessions');

    expect(res.status).toBe(200);
    expect(res.body[0]).toHaveProperty('id');
    expect(res.body[0]).toHaveProperty('created_at');
    expect(res.body[0]).toHaveProperty('closed_at');
    expect(res.body[0]).toHaveProperty('is_active');
    expect(res.body[0]).toHaveProperty('games_played');
  });
});

describe('GET /api/sessions/:id notes visibility', () => {
  beforeEach(() => {
    cleanDb();
  });

  test('returns full notes when authenticated', async () => {
    const session = seedSession({ notes: '**Full notes** here\n\nSecond paragraph' });

    const res = await request(app)
      .get(`/api/sessions/${session.id}`)
      .set('Authorization', getAuthHeader());

    expect(res.status).toBe(200);
    expect(res.body.notes).toBe('**Full notes** here\n\nSecond paragraph');
    expect(res.body.has_notes).toBe(true);
    expect(res.body.notes_preview).toBe('Full notes here');
  });

  test('returns only preview when unauthenticated', async () => {
    const session = seedSession({ notes: '**Full notes** here\n\nSecond paragraph' });

    const res = await request(app)
      .get(`/api/sessions/${session.id}`);

    expect(res.status).toBe(200);
    expect(res.body.notes).toBeUndefined();
    expect(res.body.has_notes).toBe(true);
    expect(res.body.notes_preview).toBe('Full notes here');
  });

  test('returns has_notes false when no notes', async () => {
    const session = seedSession({ notes: null });

    const res = await request(app)
      .get(`/api/sessions/${session.id}`);

    expect(res.status).toBe(200);
    expect(res.body.has_notes).toBe(false);
    expect(res.body.notes_preview).toBeNull();
  });
});

describe('PUT /api/sessions/:id/notes', () => {
  beforeEach(() => {
    cleanDb();
  });

  test('updates notes when authenticated', async () => {
    const session = seedSession({ notes: 'Old notes' });

    const res = await request(app)
      .put(`/api/sessions/${session.id}/notes`)
      .set('Authorization', getAuthHeader())
      .set('Content-Type', 'application/json')
      .send({ notes: 'New notes here' });

    expect(res.status).toBe(200);
    expect(res.body.notes).toBe('New notes here');
  });

  test('overwrites notes completely (no merge)', async () => {
    const session = seedSession({ notes: 'Original notes' });

    const res = await request(app)
      .put(`/api/sessions/${session.id}/notes`)
      .set('Authorization', getAuthHeader())
      .set('Content-Type', 'application/json')
      .send({ notes: 'Replacement' });

    expect(res.status).toBe(200);
    expect(res.body.notes).toBe('Replacement');
  });

  test('returns 404 for nonexistent session', async () => {
    const res = await request(app)
      .put('/api/sessions/99999/notes')
      .set('Authorization', getAuthHeader())
      .set('Content-Type', 'application/json')
      .send({ notes: 'test' });

    expect(res.status).toBe(404);
  });

  test('returns 401 without auth header', async () => {
    const session = seedSession({});

    const res = await request(app)
      .put(`/api/sessions/${session.id}/notes`)
      .set('Content-Type', 'application/json')
      .send({ notes: 'test' });

    expect(res.status).toBe(401);
  });

  test('returns 403 with invalid token', async () => {
    const session = seedSession({});

    const res = await request(app)
      .put(`/api/sessions/${session.id}/notes`)
      .set('Authorization', 'Bearer invalid-token')
      .set('Content-Type', 'application/json')
      .send({ notes: 'test' });

    expect(res.status).toBe(403);
  });
});

describe('DELETE /api/sessions/:id/notes', () => {
  beforeEach(() => {
    cleanDb();
  });

  test('clears notes when authenticated', async () => {
    const session = seedSession({ notes: 'Some notes' });

    const res = await request(app)
      .delete(`/api/sessions/${session.id}/notes`)
      .set('Authorization', getAuthHeader());

    expect(res.status).toBe(200);
    expect(res.body.success).toBe(true);

    // Verify notes are actually cleared
    const check = await request(app)
      .get(`/api/sessions/${session.id}`)
      .set('Authorization', getAuthHeader());
    expect(check.body.notes).toBeNull();
    expect(check.body.has_notes).toBe(false);
  });

  test('returns 404 for nonexistent session', async () => {
    const res = await request(app)
      .delete('/api/sessions/99999/notes')
      .set('Authorization', getAuthHeader());

    expect(res.status).toBe(404);
  });

  test('returns 401 without auth header', async () => {
    const session = seedSession({ notes: 'test' });

    const res = await request(app)
      .delete(`/api/sessions/${session.id}/notes`);

    expect(res.status).toBe(401);
  });

  test('returns 403 with invalid token', async () => {
    const session = seedSession({ notes: 'test' });

    const res = await request(app)
      .delete(`/api/sessions/${session.id}/notes`)
      .set('Authorization', 'Bearer invalid-token');

    expect(res.status).toBe(403);
  });
});

