/**
 * Notification Route Tests
 *
 * Tests notification configuration, test delivery, and history endpoints.
 * Notifications are mounted at /api/notifications/ prefix.
 */

const request = require('supertest');
const fs = require('fs');
const path = require('path');
const os = require('os');

const testServicesFile = path.join(os.tmpdir(), `notifications-services-${Date.now()}.json`);
const testConfigFile = path.join(os.tmpdir(), `notifications-config-${Date.now()}.json`);

process.env.SERVICES_FILE = testServicesFile;
process.env.CONFIG_FILE = testConfigFile;
process.env.ENABLE_HEALTH_CHECKER = 'false';
process.env.NODE_ENV = 'test';

fs.writeFileSync(testServicesFile, '[]', 'utf8');
fs.writeFileSync(testConfigFile, '{}', 'utf8');

const app = require('../server');

describe('Notification Routes', () => {
  afterAll(() => {
    try { fs.unlinkSync(testServicesFile); } catch (e) { /* ignore */ }
    try { fs.unlinkSync(testConfigFile); } catch (e) { /* ignore */ }
  });

  describe('GET /api/notifications/config', () => {
    test('should return 200 with config object', async () => {
      const res = await request(app).get('/api/notifications/config');

      expect(res.statusCode).toBe(200);
      expect(res.body.success).toBe(true);
      expect(res.body).toHaveProperty('config');
      expect(res.body.config).toHaveProperty('enabled');
      expect(res.body.config).toHaveProperty('providers');
      expect(res.body.config.providers).toHaveProperty('discord');
      expect(res.body.config.providers).toHaveProperty('telegram');
      expect(res.body.config.providers).toHaveProperty('ntfy');
    });

    test('should redact sensitive provider data', async () => {
      const res = await request(app).get('/api/notifications/config');

      expect(res.statusCode).toBe(200);
      // Should show enabled/configured flags, not raw webhook URLs or tokens
      const discord = res.body.config.providers.discord;
      expect(discord).toHaveProperty('enabled');
      expect(discord).toHaveProperty('configured');
      expect(discord).not.toHaveProperty('webhookUrl');
    });
  });

  describe('POST /api/notifications/config', () => {
    test('should return 200 when updating enabled state', async () => {
      const res = await request(app)
        .post('/api/notifications/config')
        .send({ enabled: true });

      expect(res.statusCode).toBe(200);
      expect(res.body.success).toBe(true);
      expect(res.body.message).toContain('updated');
    });

    test('should return 200 when updating event settings', async () => {
      const res = await request(app)
        .post('/api/notifications/config')
        .send({
          events: {
            containerDown: true,
            containerUp: false
          }
        });

      expect(res.statusCode).toBe(200);
      expect(res.body.success).toBe(true);
    });

    test('should reject invalid Discord webhook URL', async () => {
      const res = await request(app)
        .post('/api/notifications/config')
        .send({
          providers: {
            discord: {
              enabled: true,
              webhookUrl: 'not-a-valid-url'
            }
          }
        });

      expect(res.statusCode).toBe(400);
    });

    test('should reject invalid ntfy topic', async () => {
      const res = await request(app)
        .post('/api/notifications/config')
        .send({
          providers: {
            ntfy: {
              enabled: true,
              topic: 'invalid topic with spaces!!!'
            }
          }
        });

      expect(res.statusCode).toBe(400);
    });
  });

  describe('POST /api/notifications/test', () => {
    test('should handle test with unknown provider', async () => {
      const res = await request(app)
        .post('/api/notifications/test')
        .send({ provider: 'unknown_provider' });

      expect(res.statusCode).toBe(400);
    });

    test('should handle test with no provider (tests all enabled)', async () => {
      const res = await request(app)
        .post('/api/notifications/test')
        .send({});

      // When no providers are configured, should still return 200
      // with sent: true (but results array may be empty or have failures)
      expect([200, 400]).toContain(res.statusCode);
      if (res.statusCode === 200) {
        expect(res.body.success).toBe(true);
      }
    });

    test('should handle discord test gracefully when not configured', async () => {
      const res = await request(app)
        .post('/api/notifications/test')
        .send({ provider: 'discord' });

      // Discord test without a webhook URL configured will fail
      // but should still return 200 with success: false
      expect(res.statusCode).toBe(200);
      expect(res.body).toHaveProperty('success');
      expect(res.body.provider).toBe('discord');
    });
  });

  describe('GET /api/notifications/history', () => {
    test('should return 200 with history array', async () => {
      const res = await request(app).get('/api/notifications/history');

      expect(res.statusCode).toBe(200);
      expect(res.body.success).toBe(true);
      expect(res.body).toHaveProperty('history');
      expect(Array.isArray(res.body.history)).toBe(true);
      expect(res.body).toHaveProperty('total');
      expect(typeof res.body.total).toBe('number');
    });

    test('should respect limit query parameter', async () => {
      const res = await request(app)
        .get('/api/notifications/history')
        .query({ limit: 10 });

      expect(res.statusCode).toBe(200);
      expect(res.body.success).toBe(true);
      expect(res.body.history.length).toBeLessThanOrEqual(10);
    });
  });

  describe('DELETE /api/notifications/history', () => {
    test('should clear notification history', async () => {
      const res = await request(app).delete('/api/notifications/history');

      expect(res.statusCode).toBe(200);
      expect(res.body.success).toBe(true);
      expect(res.body.message).toContain('cleared');
    });
  });
});
