import { describe, it, expect } from 'vitest';
import { generateStaticMockCode } from './static-mock-generator';
import type { Schema } from '../types';

describe('Static Mock Generator', () => {
  describe('generateStaticMockCode', () => {
    it('generates correct mock for string with email format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'email',
      };
      const result = generateStaticMockCode(schema, 'Email');
      expect(result).toBe('"user@example.com"');
    });

    it('generates correct mock for string with uuid format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'uuid',
      };
      const result = generateStaticMockCode(schema, 'UUID');
      expect(result).toBe('"550e8400-e29b-41d4-a716-446655440000"');
    });

    it('generates correct mock for string with url format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'url',
      };
      const result = generateStaticMockCode(schema, 'URL');
      expect(result).toBe('"https://example.com"');
    });

    it('generates correct mock for string with date format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'date',
      };
      const result = generateStaticMockCode(schema, 'Date');
      expect(result).toBe('"2024-01-01"');
    });

    it('generates correct mock for string with date-time format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'date-time',
      };
      const result = generateStaticMockCode(schema, 'DateTime');
      expect(result).toBe('"2024-01-01T00:00:00.000Z"');
    });

    it('generates correct mock for plain string', () => {
      const schema: Schema = {
        type: 'string',
      };
      const result = generateStaticMockCode(schema, 'String');
      expect(result).toBe('"aaaaa"');
    });

    it('respects minLength for strings', () => {
      const schema: Schema = {
        type: 'string',
        minLength: 10,
      };
      const result = generateStaticMockCode(schema, 'String');
      expect(result).toBe('"aaaaaaaaaa"');
    });

    it('generates correct mock for number', () => {
      const schema: Schema = {
        type: 'number',
        minimum: 0,
        maximum: 100,
      };
      const result = generateStaticMockCode(schema, 'Number');
      expect(result).toBe('50');
    });

    it('generates correct mock for integer', () => {
      const schema: Schema = {
        type: 'integer',
        minimum: 0,
        maximum: 10,
      };
      const result = generateStaticMockCode(schema, 'Integer');
      expect(result).toBe('5');
    });

    it('generates correct mock for boolean', () => {
      const schema: Schema = {
        type: 'boolean',
      };
      const result = generateStaticMockCode(schema, 'Boolean');
      expect(result).toBe('true');
    });

    it('generates correct mock for enum', () => {
      const schema: Schema = {
        enum: ['active', 'inactive', 'pending'],
      };
      const result = generateStaticMockCode(schema, 'Status');
      expect(result).toBe('"active"');
    });

    it('generates correct mock for array', () => {
      const schema: Schema = {
        type: 'array',
        items: {
          type: 'string',
        },
      };
      const result = generateStaticMockCode(schema, 'StringArray');
      expect(result).toBe('["aaaaa"]');
    });

    it('generates correct mock for simple object', () => {
      const schema: Schema = {
        type: 'object',
        properties: {
          id: { type: 'string', format: 'uuid' },
          name: { type: 'string' },
        },
        required: ['id', 'name'],
      };
      const result = generateStaticMockCode(schema, 'User');
      expect(result).toContain('id: "550e8400-e29b-41d4-a716-446655440000"');
      expect(result).toContain('name: "aaaaa"');
    });

    it('only includes required properties in objects', () => {
      const schema: Schema = {
        type: 'object',
        properties: {
          id: { type: 'string' },
          name: { type: 'string' },
          optional: { type: 'string' },
        },
        required: ['id', 'name'],
      };
      const result = generateStaticMockCode(schema, 'User');
      expect(result).toContain('id:');
      expect(result).toContain('name:');
      expect(result).not.toContain('optional:');
    });

    it('handles nested objects', () => {
      const schema: Schema = {
        type: 'object',
        properties: {
          user: {
            type: 'object',
            properties: {
              id: { type: 'string' },
              name: { type: 'string' },
            },
            required: ['id'],
          },
        },
        required: ['user'],
      };
      const result = generateStaticMockCode(schema, 'Wrapper');
      expect(result).toContain('user:');
      expect(result).toContain('id:');
    });

    it('uses default value if provided', () => {
      const schema: Schema = {
        type: 'string',
        default: 'default-value',
      };
      const result = generateStaticMockCode(schema, 'String');
      expect(result).toBe('"default-value"');
    });

    it('uses example value if provided', () => {
      const schema: Schema = {
        type: 'number',
        examples: [42],
      };
      const result = generateStaticMockCode(schema, 'Number');
      expect(result).toBe('42');
    });

    it('handles const value in schema default/example', () => {
      const schema: Schema = {
        type: 'string',
        default: 'constant-value',
      };
      const result = generateStaticMockCode(schema, 'Const');
      expect(result).toBe('"constant-value"');
    });

    it('handles oneOf schemas', () => {
      const schema: Schema = {
        oneOf: [{ type: 'string' }, { type: 'number' }],
      };
      const result = generateStaticMockCode(schema, 'Union');

      expect(result).toBe('null');
    });

    it('handles anyOf schemas with enums', () => {
      const schema: Schema = {
        anyOf: [{ const: 'value1' }, { const: 'value2' }],
      };
      const result = generateStaticMockCode(schema, 'AnyUnion');
      expect(result).toBe('"value1"');
    });

    it('handles allOf schemas', () => {
      const schema: Schema = {
        allOf: [
          {
            type: 'object',
            properties: {
              name: { type: 'string' },
            },
          },
          {
            type: 'object',
            properties: {
              age: { type: 'number' },
            },
          },
        ],
      };
      const result = generateStaticMockCode(schema, 'Combined');

      expect(result).toBe('null');
    });

    it('handles number with minimum constraint', () => {
      const schema: Schema = {
        type: 'number',
        minimum: 100,
      };
      const result = generateStaticMockCode(schema, 'MinNum');
      const value = Number(result);
      expect(value).toBeGreaterThanOrEqual(100);
    });

    it('handles number with maximum constraint', () => {
      const schema: Schema = {
        type: 'number',
        maximum: 10,
      };
      const result = generateStaticMockCode(schema, 'MaxNum');
      const value = Number(result);
      expect(value).toBeLessThanOrEqual(10);
    });

    it('handles integer type specifically', () => {
      const schema: Schema = {
        type: 'integer',
      };
      const result = generateStaticMockCode(schema, 'Int');
      const value = Number(result);
      expect(Number.isInteger(value)).toBe(true);
    });

    it('handles string with minLength', () => {
      const schema: Schema = {
        type: 'string',
        minLength: 20,
      };
      const result = generateStaticMockCode(schema, 'LongString');
      const unquoted = result.slice(1, -1);
      expect(unquoted.length).toBeGreaterThanOrEqual(20);
    });

    it('handles string with maxLength', () => {
      const schema: Schema = {
        type: 'string',
        maxLength: 5,
      };
      const result = generateStaticMockCode(schema, 'ShortString');
      const unquoted = result.slice(1, -1);
      expect(unquoted.length).toBeLessThanOrEqual(5);
    });

    it('handles string with pattern as placeholder', () => {
      const schema: Schema = {
        type: 'string',
        pattern: '^[0-9]{3}$',
      };
      const result = generateStaticMockCode(schema, 'Pattern');

      expect(result).toBe('"pattern-match"');
    });

    it('handles uuid format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'uuid',
      };
      const result = generateStaticMockCode(schema, 'UUID');
      const unquoted = result.slice(1, -1);
      expect(
        /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/.test(unquoted)
      ).toBe(true);
    });

    it('handles email format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'email',
      };
      const result = generateStaticMockCode(schema, 'Email');
      const unquoted = result.slice(1, -1);
      expect(unquoted).toMatch(/@/);
    });

    it('handles uri/url format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'uri',
      };
      const result = generateStaticMockCode(schema, 'URI');
      const unquoted = result.slice(1, -1);
      expect(unquoted).toMatch(/^https?:\/\//);
    });

    it('handles date-time format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'date-time',
      };
      const result = generateStaticMockCode(schema, 'DateTime');
      const unquoted = result.slice(1, -1);
      expect(!isNaN(Date.parse(unquoted))).toBe(true);
    });

    it('handles date format', () => {
      const schema: Schema = {
        type: 'string',
        format: 'date',
      };
      const result = generateStaticMockCode(schema, 'Date');
      const unquoted = result.slice(1, -1);
      expect(/^\d{4}-\d{2}-\d{2}$/.test(unquoted)).toBe(true);
    });

    it('handles time format with fallback', () => {
      const schema: Schema = {
        type: 'string',
        format: 'time',
      };
      const result = generateStaticMockCode(schema, 'Time');

      expect(typeof result).toBe('string');
      expect(result.length).toBeGreaterThan(0);
    });

    it('handles array with minItems', () => {
      const schema: Schema = {
        type: 'array',
        items: { type: 'number' },
        minItems: 5,
      };
      const result = generateStaticMockCode(schema, 'MinArray');
      const arr = JSON.parse(result);
      expect(arr.length).toBeGreaterThanOrEqual(5);
    });

    it('handles array with maxItems', () => {
      const schema: Schema = {
        type: 'array',
        items: { type: 'string' },
        maxItems: 2,
      };
      const result = generateStaticMockCode(schema, 'MaxArray');
      const arr = JSON.parse(result);
      expect(arr.length).toBeLessThanOrEqual(2);
    });

    it('handles null type', () => {
      const schema: Schema = {
        type: 'null',
      };
      const result = generateStaticMockCode(schema, 'Null');
      expect(result).toBe('null');
    });

    it('handles nullable string', () => {
      const schema: Schema = {
        type: 'string',
        nullable: true,
      };
      const result = generateStaticMockCode(schema, 'NullableString');
      expect(typeof result).toBe('string');
    });

    it('handles empty object without properties', () => {
      const schema: Schema = {
        type: 'object',
      };
      const result = generateStaticMockCode(schema, 'EmptyObj');
      expect(result).toBe('{}');
    });

    it('handles complex nested structures', () => {
      const schema: Schema = {
        type: 'object',
        properties: {
          users: {
            type: 'array',
            items: {
              type: 'object',
              properties: {
                profile: {
                  type: 'object',
                  properties: {
                    name: { type: 'string' },
                  },
                  required: ['name'],
                },
              },
              required: ['profile'],
            },
          },
        },
        required: ['users'],
      };
      const result = generateStaticMockCode(schema, 'Nested');
      expect(result).toContain('users:');
      expect(result).toContain('profile:');
      expect(result).toContain('name:');
    });

    it('handles schema without type', () => {
      const schema: Schema = {};
      const result = generateStaticMockCode(schema, 'Unknown');
      expect(result).toBeTruthy();
    });

    it('handles multipleOf constraint for numbers', () => {
      const schema: Schema = {
        type: 'number',
        multipleOf: 5,
      };
      const result = generateStaticMockCode(schema, 'Multiple');
      const value = Number(result);
      expect(value % 5).toBe(0);
    });

    it('handles number constraints with min and max', () => {
      const schema: Schema = {
        type: 'number',
        minimum: 10,
        maximum: 20,
      };
      const result = generateStaticMockCode(schema, 'Constrained');
      const value = Number(result);
      expect(value).toBeGreaterThanOrEqual(10);
      expect(value).toBeLessThanOrEqual(20);
    });
  });
});
