import { describe, expect, it, beforeEach, afterEach } from 'vitest';
import {
  baseEnvSchema,
  loadConfig,
  loadProductIdentity,
  getProductId,
  _resetProductIdentity,
} from '../index.js';

describe('baseEnvSchema', () => {
  it('provides defaults for PORT, HOST, NODE_ENV, COSMOS_DATABASE', () => {
    const result = baseEnvSchema.parse({
      SERVICE_NAME: 'test-svc',
      COSMOS_ENDPOINT: 'https://test.cosmos.azure.com:443/',
      COSMOS_KEY: 'key==',
    });
    expect(result.PORT).toBe(3000);
    expect(result.HOST).toBe('0.0.0.0');
    expect(result.NODE_ENV).toBe('development');
    expect(result.COSMOS_DATABASE).toBe('lysnrai');
  });

  it('rejects missing SERVICE_NAME', () => {
    expect(() =>
      baseEnvSchema.parse({
        COSMOS_ENDPOINT: 'https://test.cosmos.azure.com:443/',
        COSMOS_KEY: 'key==',
      })
    ).toThrow();
  });

  it('rejects missing COSMOS_ENDPOINT', () => {
    expect(() =>
      baseEnvSchema.parse({
        SERVICE_NAME: 'svc',
        COSMOS_KEY: 'key==',
      })
    ).toThrow();
  });

  it('rejects missing COSMOS_KEY', () => {
    expect(() =>
      baseEnvSchema.parse({
        SERVICE_NAME: 'svc',
        COSMOS_ENDPOINT: 'https://test.cosmos.azure.com:443/',
      })
    ).toThrow();
  });

  it('coerces PORT from string', () => {
    const result = baseEnvSchema.parse({
      PORT: '4003',
      SERVICE_NAME: 'svc',
      COSMOS_ENDPOINT: 'https://test.cosmos.azure.com:443/',
      COSMOS_KEY: 'key==',
    });
    expect(result.PORT).toBe(4003);
  });

  it('accepts valid NODE_ENV values', () => {
    for (const env of ['development', 'production', 'test']) {
      const result = baseEnvSchema.parse({
        NODE_ENV: env,
        SERVICE_NAME: 'svc',
        COSMOS_ENDPOINT: 'https://test.cosmos.azure.com:443/',
        COSMOS_KEY: 'key==',
      });
      expect(result.NODE_ENV).toBe(env);
    }
  });

  it('rejects invalid NODE_ENV', () => {
    expect(() =>
      baseEnvSchema.parse({
        NODE_ENV: 'staging',
        SERVICE_NAME: 'svc',
        COSMOS_ENDPOINT: 'https://test.cosmos.azure.com:443/',
        COSMOS_KEY: 'key==',
      })
    ).toThrow();
  });
});

describe('loadConfig', () => {
  const origEnv = process.env;

  beforeEach(() => {
    process.env = {
      ...origEnv,
      SERVICE_NAME: 'test-svc',
      COSMOS_ENDPOINT: 'https://test.cosmos.azure.com:443/',
      COSMOS_KEY: 'key==',
    };
  });

  afterEach(() => {
    process.env = origEnv;
  });

  it('parses base env without extension', () => {
    const config = loadConfig();
    expect(config.SERVICE_NAME).toBe('test-svc');
    expect(config.PORT).toBe(3000);
  });

  it('extends with additional fields', async () => {
    process.env.STRIPE_KEY = 'sk_test_123';
    const { z } = await import('zod');
    const config = loadConfig({ STRIPE_KEY: z.string().min(1) });
    expect(config.STRIPE_KEY).toBe('sk_test_123');
    expect(config.SERVICE_NAME).toBe('test-svc');
  });

  it('throws on missing required extension field', async () => {
    const { z } = await import('zod');
    expect(() => loadConfig({ MISSING_FIELD: z.string().min(1) })).toThrow();
  });
});

describe('productIdentity', () => {
  beforeEach(() => {
    _resetProductIdentity();
  });

  it('falls back to env vars', () => {
    process.env.PRODUCT_ID = 'testprod';
    process.env.DISPLAY_NAME = 'TestProd';
    const identity = loadProductIdentity();
    expect(identity.productId).toBe('testprod');
    expect(identity.displayName).toBe('TestProd');
    delete process.env.PRODUCT_ID;
    delete process.env.DISPLAY_NAME;
  });

  it('defaults to lysnrai when no env or file', () => {
    delete process.env.PRODUCT_ID;
    const identity = loadProductIdentity();
    expect(identity.productId).toBe('lysnrai');
    expect(identity.displayName).toBe('LysnrAI');
    expect(identity.licensePrefix).toBe('LYSNR');
  });

  it('getProductId returns just the ID', () => {
    _resetProductIdentity();
    delete process.env.PRODUCT_ID;
    expect(getProductId()).toBe('lysnrai');
  });

  it('caches identity after first load', () => {
    delete process.env.PRODUCT_ID;
    const id1 = loadProductIdentity();
    process.env.PRODUCT_ID = 'changed';
    const id2 = loadProductIdentity();
    expect(id1).toBe(id2); // same cached object
    delete process.env.PRODUCT_ID;
  });

  it('_resetProductIdentity clears cache', () => {
    delete process.env.PRODUCT_ID;
    loadProductIdentity();
    _resetProductIdentity();
    process.env.PRODUCT_ID = 'newprod';
    const fresh = loadProductIdentity();
    expect(fresh.productId).toBe('newprod');
    delete process.env.PRODUCT_ID;
  });
});
