/**
 * DC-100: Service discovery tests
 */
const express = require('express');
const request = require('supertest');

function createApp(docker, servicesStateManager) {
  const app = express();
  app.use(express.json());

  const asyncHandler = (fn) => (req, res, next) => Promise.resolve(fn(req, res, next)).catch(next);
  const discoverRoutes = require('../../routes/discover');

  app.use('/api/v1', discoverRoutes({
    docker,
    servicesStateManager,
    asyncHandler,
  }));
  return app;
}

describe('DC-100: Service Discovery', () => {
  it('returns 503 when Docker is not available', async () => {
    const app = createApp(null, null);
    const res = await request(app).get('/api/v1/discover');
    expect(res.status).toBe(503);
    expect(res.body.success).toBe(false);
    expect(res.body.code).toBe('DC-CONT-011');
  });

  it('discovers running containers with pattern matching', async () => {
    const mockDocker = {
      client: {
        listContainers: jest.fn().mockResolvedValue([
          {
            Id: 'abc123def456',
            Names: ['/plex-server'],
            Image: 'plexinc/pms-docker:latest',
            State: 'running',
            Ports: [
              { IP: '0.0.0.0', PrivatePort: 32400, PublicPort: 32400, Type: 'tcp' },
            ],
            Labels: {},
          },
          {
            Id: 'def789abc012',
            Names: ['/redis-cache'],
            Image: 'redis:7-alpine',
            State: 'running',
            Ports: [
              { IP: '0.0.0.0', PrivatePort: 6379, PublicPort: 6379, Type: 'tcp' },
            ],
            Labels: {},
          },
        ]),
      },
    };

    const mockStateManager = {
      read: jest.fn().mockResolvedValue([]),
    };

    const app = createApp(mockDocker, mockStateManager);
    const res = await request(app).get('/api/v1/discover');

    expect(res.status).toBe(200);
    expect(res.body.success).toBe(true);
    expect(res.body.total).toBe(2);
    expect(res.body.discovered).toHaveLength(2);

    const plex = res.body.discovered.find(d => d.name === 'plex-server');
    expect(plex.suggested.type).toBe('plex');
    expect(plex.suggested.name).toBe('Plex');
    expect(plex.suggested.port).toBe(32400);
    expect(plex.existing).toBe(false);

    const redis = res.body.discovered.find(d => d.name === 'redis-cache');
    expect(redis.suggested.type).toBe('redis');
  });

  it('marks already-added services as existing', async () => {
    const mockDocker = {
      client: {
        listContainers: jest.fn().mockResolvedValue([
          {
            Id: 'abc123def456',
            Names: ['/plex-server'],
            Image: 'plexinc/pms-docker:latest',
            State: 'running',
            Ports: [],
            Labels: {},
          },
        ]),
      },
    };

    const mockStateManager = {
      read: jest.fn().mockResolvedValue([{ id: 'plex-server' }]),
    };

    const app = createApp(mockDocker, mockStateManager);
    const res = await request(app).get('/api/v1/discover');

    expect(res.status).toBe(200);
    expect(res.body.discovered[0].existing).toBe(true);
  });

  it('handles empty container list', async () => {
    const mockDocker = {
      client: {
        listContainers: jest.fn().mockResolvedValue([]),
      },
    };

    const app = createApp(mockDocker, null);
    const res = await request(app).get('/api/v1/discover');

    expect(res.status).toBe(200);
    expect(res.body.total).toBe(0);
    expect(res.body.discovered).toEqual([]);
  });

  it('returns 500 on Docker error', async () => {
    const mockDocker = {
      client: {
        listContainers: jest.fn().mockRejectedValue(new Error('connection refused')),
      },
    };

    const app = createApp(mockDocker, null);
    const res = await request(app).get('/api/v1/discover');

    expect(res.status).toBe(500);
    expect(res.body.success).toBe(false);
  });
});
