import express from 'express';
import request from 'supertest';

import { setupSwagger, specs } from '../swagger';

// EN: Import actual swagger specs for testing
// VI: Import actual swagger specs để test

// EN: Type assertion for OpenAPI spec
// VI: Type assertion cho OpenAPI spec
interface OpenAPISpec {
  openapi: string;
  info: {
    title: string;
    version: string;
    [key: string]: any;
  };
  servers?: Array<{ url: string; [key: string]: any }>;
  components?: {
    securitySchemes?: {
      [key: string]: any;
    };
    schemas?: {
      [key: string]: any;
    };
    [key: string]: any;
  };
  [key: string]: any;
}

const typedSpecs = specs as OpenAPISpec;

describe('Swagger Documentation', () => {
  let app: express.Application;

  beforeEach(() => {
    app = express();
    app.use(express.json());
    // Reset mock
    (setupSwagger as jest.Mock).mockClear();
  });

  describe('specs', () => {
    it('should have valid OpenAPI structure', () => {
      expect(typedSpecs.openapi).toBe('3.0.0');
      expect(typedSpecs.info).toBeDefined();
      expect(typedSpecs.info.title).toBe('Microservice Template API');
      expect(typedSpecs.info.version).toBe('1.0.0');
      expect(typedSpecs.servers).toBeDefined();
      expect(typedSpecs.components).toBeDefined();
    });

    it('should define security schemes', () => {
      expect(typedSpecs.components?.securitySchemes).toBeDefined();
      expect(typedSpecs.components?.securitySchemes?.bearerAuth).toBeDefined();
      expect(typedSpecs.components?.securitySchemes?.bearerAuth.type).toBe('http');
      expect(typedSpecs.components?.securitySchemes?.bearerAuth.scheme).toBe('bearer');
    });

    it('should define response schemas', () => {
      const schemas = typedSpecs.components?.schemas;
      expect(schemas?.ApiResponse).toBeDefined();
      expect(schemas?.ErrorResponse).toBeDefined();
      expect(schemas?.Feature).toBeDefined();
      expect(schemas?.CreateFeatureRequest).toBeDefined();
      expect(schemas?.UpdateFeatureRequest).toBeDefined();
      expect(schemas?.UserInfo).toBeDefined();
    });

    it('should have server configurations', () => {
      expect(typedSpecs.servers).toBeInstanceOf(Array);
      expect(typedSpecs.servers && typedSpecs.servers.length).toBeGreaterThan(0);
      expect(typedSpecs.servers?.[0]?.url).toContain('localhost');
    });
  });

  describe('setupSwagger', () => {
    it('should be callable', () => {
      expect(typeof setupSwagger).toBe('function');
    });

    it('should accept app and basePath parameters', () => {
      const mockApp = {
        use: jest.fn(),
        get: jest.fn(),
      } as any;

      setupSwagger(mockApp, '/docs');

      expect(setupSwagger).toHaveBeenCalledWith(mockApp, '/docs');
    });
  });

  describe('Swagger UI endpoints', () => {
    beforeEach(() => {
      // Setup real swagger for integration test
      const realSetupSwagger = jest.requireActual('../swagger').setupSwagger;
      realSetupSwagger(app, '/test-docs');
    });

    it('should serve swagger json endpoint', async () => {
      const response = await request(app)
        .get('/test-docs.json')
        .expect(200);

      expect(response.headers['content-type']).toContain('application/json');
      expect(response.body.openapi).toBe('3.0.0');
    });

    it('should serve swagger yaml endpoint', async () => {
      const response = await request(app)
        .get('/test-docs.yaml')
        .expect(200);

      expect(response.headers['content-type']).toContain('application/yaml');
      expect(response.text).toBeDefined();
    });
  });
});