import { describe, it, expect } from 'vitest';
import {
  AuthProviderConfigSchema,
  AuthPluginConfigSchema,
  AuthConfigSchema,
  MutualTLSConfigSchema,
  SocialProviderConfigSchema,
  EmailAndPasswordConfigSchema,
  EmailVerificationConfigSchema,
  AdvancedAuthConfigSchema,
} from './auth-config.zod';

describe('AuthProviderConfigSchema', () => {
  it('should accept valid provider config', () => {
    const config = AuthProviderConfigSchema.parse({
      id: 'github',
      clientId: 'abc123',
      clientSecret: 'secret456',
    });

    expect(config.id).toBe('github');
    expect(config.clientId).toBe('abc123');
    expect(config.clientSecret).toBe('secret456');
  });

  it('should accept optional scope', () => {
    const config = AuthProviderConfigSchema.parse({
      id: 'google',
      clientId: 'abc123',
      clientSecret: 'secret456',
      scope: ['email', 'profile'],
    });

    expect(config.scope).toEqual(['email', 'profile']);
  });

  it('should reject missing required fields', () => {
    expect(() => AuthProviderConfigSchema.parse({})).toThrow();
    expect(() => AuthProviderConfigSchema.parse({ id: 'github' })).toThrow();
    expect(() => AuthProviderConfigSchema.parse({ id: 'github', clientId: 'abc' })).toThrow();
  });
});

describe('AuthPluginConfigSchema', () => {
  it('should apply defaults for all fields', () => {
    const config = AuthPluginConfigSchema.parse({});

    expect(config.organization).toBe(true);
    expect(config.twoFactor).toBe(false);
    expect(config.passkeys).toBe(false);
    expect(config.magicLink).toBe(false);
  });

  it('should accept custom values', () => {
    const config = AuthPluginConfigSchema.parse({
      organization: true,
      twoFactor: true,
      passkeys: true,
      magicLink: true,
    });

    expect(config.organization).toBe(true);
    expect(config.twoFactor).toBe(true);
    expect(config.passkeys).toBe(true);
    expect(config.magicLink).toBe(true);
  });
});

describe('AuthConfigSchema', () => {
  it('should accept minimal configuration', () => {
    const config = AuthConfigSchema.parse({});

    expect(config.secret).toBeUndefined();
    expect(config.baseUrl).toBeUndefined();
    expect(config.providers).toBeUndefined();
    expect(config.plugins).toBeUndefined();
    expect(config.session).toBeUndefined();
  });

  it('should accept full configuration', () => {
    const config = AuthConfigSchema.parse({
      secret: 'my-secret',
      baseUrl: 'https://auth.example.com',
      databaseUrl: 'postgres://localhost/auth',
      providers: [
        { id: 'github', clientId: 'abc', clientSecret: 'def' },
      ],
      plugins: { organization: true, twoFactor: true },
      session: { expiresIn: 3600, updateAge: 600 },
    });

    expect(config.secret).toBe('my-secret');
    expect(config.baseUrl).toBe('https://auth.example.com');
    expect(config.providers).toHaveLength(1);
    expect(config.plugins?.organization).toBe(true);
    expect(config.session?.expiresIn).toBe(3600);
  });

  it('should apply session defaults', () => {
    const config = AuthConfigSchema.parse({
      session: {},
    });

    expect(config.session?.expiresIn).toBe(60 * 60 * 24 * 7);
    expect(config.session?.updateAge).toBe(60 * 60 * 24);
  });

  it('should allow extra properties via catchall', () => {
    const config = AuthConfigSchema.parse({
      customSetting: 'value',
    });

    expect(config.customSetting).toBe('value');
  });

  it('should accept trustedOrigins as an array of strings', () => {
    const config = AuthConfigSchema.parse({
      trustedOrigins: ['https://*.example.com', 'http://localhost:3000'],
    });

    expect(config.trustedOrigins).toEqual(['https://*.example.com', 'http://localhost:3000']);
  });

  it('should accept empty trustedOrigins array', () => {
    const config = AuthConfigSchema.parse({
      trustedOrigins: [],
    });

    expect(config.trustedOrigins).toEqual([]);
  });

  it('should allow trustedOrigins to be omitted', () => {
    const config = AuthConfigSchema.parse({});

    expect(config.trustedOrigins).toBeUndefined();
  });
});

// ==========================================
// Mutual TLS Configuration Tests
// ==========================================

describe('MutualTLSConfigSchema', () => {
  it('should accept minimal mTLS config', () => {
    const config = MutualTLSConfigSchema.parse({
      trustedCAs: ['/path/to/ca.pem'],
      certificateValidation: 'strict',
    });

    expect(config.enabled).toBe(false);
    expect(config.clientCertRequired).toBe(false);
    expect(config.trustedCAs).toHaveLength(1);
    expect(config.certificateValidation).toBe('strict');
  });

  it('should accept full mTLS config', () => {
    const config = MutualTLSConfigSchema.parse({
      enabled: true,
      clientCertRequired: true,
      trustedCAs: ['/path/to/ca1.pem', '/path/to/ca2.pem'],
      crlUrl: 'https://crl.example.com/crl.pem',
      ocspUrl: 'https://ocsp.example.com',
      certificateValidation: 'strict',
      allowedCNs: ['client.example.com', 'service.example.com'],
      allowedOUs: ['Engineering', 'DevOps'],
      pinning: {
        enabled: true,
        pins: ['sha256/AAAA', 'sha256/BBBB'],
      },
    });

    expect(config.enabled).toBe(true);
    expect(config.clientCertRequired).toBe(true);
    expect(config.trustedCAs).toHaveLength(2);
    expect(config.allowedCNs).toHaveLength(2);
    expect(config.allowedOUs).toHaveLength(2);
    expect(config.pinning?.enabled).toBe(true);
    expect(config.pinning?.pins).toHaveLength(2);
  });

  it('should accept all certificate validation levels', () => {
    const levels = ['strict', 'relaxed', 'none'] as const;
    levels.forEach(level => {
      const config = MutualTLSConfigSchema.parse({
        trustedCAs: [],
        certificateValidation: level,
      });
      expect(config.certificateValidation).toBe(level);
    });
  });

  it('should require trustedCAs and certificateValidation', () => {
    expect(() => MutualTLSConfigSchema.parse({})).toThrow();
    expect(() => MutualTLSConfigSchema.parse({
      trustedCAs: [],
    })).toThrow();
  });

  it('should accept mTLS in AuthConfigSchema', () => {
    const config = AuthConfigSchema.parse({
      mutualTls: {
        enabled: true,
        clientCertRequired: true,
        trustedCAs: ['/certs/ca.pem'],
        certificateValidation: 'strict',
      },
    });

    expect(config.mutualTls?.enabled).toBe(true);
    expect(config.mutualTls?.clientCertRequired).toBe(true);
  });
});

// ==========================================
// Social Provider Configuration Tests
// ==========================================

describe('SocialProviderConfigSchema', () => {
  it('should accept a map of providers', () => {
    const config = SocialProviderConfigSchema.parse({
      google: { clientId: 'gid', clientSecret: 'gsecret' },
      github: { clientId: 'ghid', clientSecret: 'ghsecret', scope: ['repo'] },
    });

    expect(config?.google.clientId).toBe('gid');
    expect(config?.github.scope).toEqual(['repo']);
  });

  it('should default enabled to true', () => {
    const config = SocialProviderConfigSchema.parse({
      google: { clientId: 'gid', clientSecret: 'gsecret' },
    });

    expect(config?.google.enabled).toBe(true);
  });

  it('should allow extra provider-specific properties via catchall', () => {
    const config = SocialProviderConfigSchema.parse({
      google: { clientId: 'gid', clientSecret: 'gsecret', accessType: 'offline' },
    });

    expect((config?.google as any).accessType).toBe('offline');
  });

  it('should accept undefined (omitted)', () => {
    const config = SocialProviderConfigSchema.parse(undefined);
    expect(config).toBeUndefined();
  });
});

// ==========================================
// Email And Password Configuration Tests
// ==========================================

describe('EmailAndPasswordConfigSchema', () => {
  it('should accept full config', () => {
    const config = EmailAndPasswordConfigSchema.parse({
      enabled: true,
      disableSignUp: false,
      requireEmailVerification: true,
      minPasswordLength: 10,
      maxPasswordLength: 64,
      autoSignIn: false,
      revokeSessionsOnPasswordReset: true,
      resetPasswordTokenExpiresIn: 7200,
    });

    expect(config?.enabled).toBe(true);
    expect(config?.minPasswordLength).toBe(10);
    expect(config?.revokeSessionsOnPasswordReset).toBe(true);
  });

  it('should default enabled to true', () => {
    const config = EmailAndPasswordConfigSchema.parse({});
    expect(config?.enabled).toBe(true);
  });

  it('should accept undefined (omitted)', () => {
    const config = EmailAndPasswordConfigSchema.parse(undefined);
    expect(config).toBeUndefined();
  });
});

// ==========================================
// Email Verification Configuration Tests
// ==========================================

describe('EmailVerificationConfigSchema', () => {
  it('should accept full config', () => {
    const config = EmailVerificationConfigSchema.parse({
      sendOnSignUp: true,
      sendOnSignIn: false,
      autoSignInAfterVerification: true,
      expiresIn: 1800,
    });

    expect(config?.sendOnSignUp).toBe(true);
    expect(config?.expiresIn).toBe(1800);
  });

  it('should accept empty object', () => {
    const config = EmailVerificationConfigSchema.parse({});
    expect(config).toBeDefined();
    expect(config?.sendOnSignUp).toBeUndefined();
  });

  it('should accept undefined (omitted)', () => {
    const config = EmailVerificationConfigSchema.parse(undefined);
    expect(config).toBeUndefined();
  });
});

// ==========================================
// Advanced Auth Configuration Tests
// ==========================================

describe('AdvancedAuthConfigSchema', () => {
  it('should accept crossSubDomainCookies', () => {
    const config = AdvancedAuthConfigSchema.parse({
      crossSubDomainCookies: {
        enabled: true,
        domain: '.objectos.app',
      },
    });

    expect(config?.crossSubDomainCookies?.enabled).toBe(true);
    expect(config?.crossSubDomainCookies?.domain).toBe('.objectos.app');
  });

  it('should accept all advanced options', () => {
    const config = AdvancedAuthConfigSchema.parse({
      crossSubDomainCookies: {
        enabled: true,
        additionalCookies: ['my_cookie'],
      },
      useSecureCookies: true,
      disableCSRFCheck: false,
      cookiePrefix: 'objectos',
    });

    expect(config?.useSecureCookies).toBe(true);
    expect(config?.cookiePrefix).toBe('objectos');
  });

  it('should accept undefined (omitted)', () => {
    const config = AdvancedAuthConfigSchema.parse(undefined);
    expect(config).toBeUndefined();
  });
});

// ==========================================
// AuthConfigSchema integration with new fields
// ==========================================

describe('AuthConfigSchema – new passthrough fields', () => {
  it('should accept socialProviders in AuthConfig', () => {
    const config = AuthConfigSchema.parse({
      socialProviders: {
        google: { clientId: 'gid', clientSecret: 'gsecret' },
      },
    });

    expect(config.socialProviders?.google.clientId).toBe('gid');
  });

  it('should accept emailAndPassword in AuthConfig', () => {
    const config = AuthConfigSchema.parse({
      emailAndPassword: {
        enabled: true,
        minPasswordLength: 12,
      },
    });

    expect(config.emailAndPassword?.minPasswordLength).toBe(12);
  });

  it('should accept emailVerification in AuthConfig', () => {
    const config = AuthConfigSchema.parse({
      emailVerification: { sendOnSignUp: true, expiresIn: 600 },
    });

    expect(config.emailVerification?.sendOnSignUp).toBe(true);
  });

  it('should accept advanced in AuthConfig', () => {
    const config = AuthConfigSchema.parse({
      advanced: {
        crossSubDomainCookies: { enabled: true, domain: '.objectos.app' },
        useSecureCookies: true,
      },
    });

    expect(config.advanced?.crossSubDomainCookies?.enabled).toBe(true);
    expect(config.advanced?.useSecureCookies).toBe(true);
  });

  it('should accept all new fields together', () => {
    const config = AuthConfigSchema.parse({
      secret: 'my-secret',
      baseUrl: 'https://app.objectos.app',
      trustedOrigins: ['https://*.objectos.app'],
      socialProviders: {
        google: { clientId: 'g', clientSecret: 's' },
        github: { clientId: 'g', clientSecret: 's' },
      },
      emailAndPassword: { enabled: true, requireEmailVerification: true },
      emailVerification: { sendOnSignUp: true },
      advanced: { crossSubDomainCookies: { enabled: true } },
    });

    expect(config.socialProviders).toBeDefined();
    expect(config.emailAndPassword?.requireEmailVerification).toBe(true);
    expect(config.emailVerification?.sendOnSignUp).toBe(true);
    expect(config.advanced?.crossSubDomainCookies?.enabled).toBe(true);
  });
});
