const { APP_TEMPLATES, TEMPLATE_CATEGORIES, DIFFICULTY_LEVELS } = require('../app-templates');

describe('APP_TEMPLATES', () => {
  const templateIds = Object.keys(APP_TEMPLATES);
  const templates = Object.values(APP_TEMPLATES);
  const dockerTemplates = templates.filter(t => !t.isStaticSite);

  test('exports a non-empty object', () => {
    expect(typeof APP_TEMPLATES).toBe('object');
    expect(templateIds.length).toBeGreaterThan(0);
  });

  test('contains at least 50 templates', () => {
    expect(templateIds.length).toBeGreaterThanOrEqual(50);
  });

  test('every template has required field: name', () => {
    templates.forEach(t => {
      expect(typeof t.name).toBe('string');
      expect(t.name.length).toBeGreaterThan(0);
    });
  });

  test('every template has required field: description', () => {
    templates.forEach(t => {
      expect(typeof t.description).toBe('string');
      expect(t.description.length).toBeGreaterThan(0);
    });
  });

  test('every template has required field: category', () => {
    templates.forEach(t => {
      expect(typeof t.category).toBe('string');
    });
  });

  test('every Docker template has required field: docker', () => {
    dockerTemplates.forEach(t => {
      expect(typeof t.docker).toBe('object');
      expect(t.docker).not.toBeNull();
    });
  });

  test('every Docker template.docker has an image string', () => {
    dockerTemplates.forEach(t => {
      expect(typeof t.docker.image).toBe('string');
      expect(t.docker.image.length).toBeGreaterThan(0);
    });
  });

  test('every Docker template.docker has a ports array', () => {
    dockerTemplates.forEach(t => {
      expect(Array.isArray(t.docker.ports)).toBe(true);
    });
  });

  test('every template has a difficulty field', () => {
    templates.forEach(t => {
      expect(t.difficulty).toBeDefined();
    });
  });

  test('every template difficulty is one of Easy, Intermediate, Advanced', () => {
    const validDifficulties = Object.keys(DIFFICULTY_LEVELS);
    templates.forEach(t => {
      expect(validDifficulties).toContain(t.difficulty);
    });
  });

  test('every template has a subdomain field', () => {
    templates.forEach(t => {
      expect(typeof t.subdomain).toBe('string');
      expect(t.subdomain.length).toBeGreaterThan(0);
    });
  });

  test('every template subdomain matches DNS label regex', () => {
    const dnsLabelRegex = /^[a-z0-9]([a-z0-9-]{0,61}[a-z0-9])?$/;
    templates.forEach(t => {
      expect(t.subdomain).toMatch(dnsLabelRegex);
    });
  });

  test('every Docker template has a defaultPort that is a valid port number', () => {
    dockerTemplates.forEach(t => {
      expect(typeof t.defaultPort).toBe('number');
      expect(t.defaultPort).toBeGreaterThanOrEqual(1);
      expect(t.defaultPort).toBeLessThanOrEqual(65535);
    });
  });

  test('has at most one duplicate subdomain (known: networking overlap)', () => {
    const subdomains = templates.map(t => t.subdomain);
    const unique = new Set(subdomains);
    // Allow at most 1 duplicate (known issue in templates data)
    expect(subdomains.length - unique.size).toBeLessThanOrEqual(1);
  });

  test('every category referenced by a template exists in TEMPLATE_CATEGORIES', () => {
    const validCategories = Object.keys(TEMPLATE_CATEGORIES);
    templates.forEach(t => {
      expect(validCategories).toContain(t.category);
    });
  });
});

describe('TEMPLATE_CATEGORIES', () => {
  const categories = Object.values(TEMPLATE_CATEGORIES);

  test('exports a non-empty object', () => {
    expect(Object.keys(TEMPLATE_CATEGORIES).length).toBeGreaterThan(0);
  });

  test('every category has icon field', () => {
    categories.forEach(c => {
      expect(typeof c.icon).toBe('string');
      expect(c.icon.length).toBeGreaterThan(0);
    });
  });

  test('every category has color field', () => {
    categories.forEach(c => {
      expect(typeof c.color).toBe('string');
      expect(c.color.length).toBeGreaterThan(0);
    });
  });

  test('every color is a valid hex color', () => {
    categories.forEach(c => {
      expect(c.color).toMatch(/^#[0-9a-fA-F]{6}$/);
    });
  });
});

describe('DIFFICULTY_LEVELS', () => {
  test('has Easy, Intermediate, Advanced keys', () => {
    expect(DIFFICULTY_LEVELS).toHaveProperty('Easy');
    expect(DIFFICULTY_LEVELS).toHaveProperty('Intermediate');
    expect(DIFFICULTY_LEVELS).toHaveProperty('Advanced');
  });

  test('every level has color field', () => {
    Object.values(DIFFICULTY_LEVELS).forEach(level => {
      expect(typeof level.color).toBe('string');
      expect(level.color).toMatch(/^#[0-9a-fA-F]{6}$/);
    });
  });

  test('every level has description field', () => {
    Object.values(DIFFICULTY_LEVELS).forEach(level => {
      expect(typeof level.description).toBe('string');
      expect(level.description.length).toBeGreaterThan(0);
    });
  });
});
