/**
 * Unit tests for Google OAuth CSRF Configuration
 *
 * Tests that the NextAuth v5 CSRF configuration is properly set up
 * to prevent MissingCSRF errors when using Google OAuth.
 *
 * Key aspects tested:
 * 1. skipCSRFCheck symbol is properly imported and used (not a boolean)
 * 2. Google OAuth provider is correctly configured
 * 3. CSRF skip is only enabled in development mode
 * 4. NextAuth route handlers are properly configured
 */

import * as fs from "fs";
import * as path from "path";

// =============================================================================
// Test Configuration & Utilities
// =============================================================================

/** File paths for configuration files under test */
const FILE_PATHS = {
  auth: path.join(process.cwd(), "lib", "auth.ts"),
  nextAuthRoute: path.join(
    process.cwd(),
    "app",
    "api",
    "auth",
    "[...nextauth]",
    "route.ts",
  ),
} as const;

/**
 * Regex patterns for validating auth configuration
 * Centralized here for easy updates when NextAuth versions change
 */
const PATTERNS = {
  // CSRF Configuration
  skipCSRFCheckImport:
    /import\s+\{[^}]*skipCSRFCheck[^}]*\}\s+from\s+['"]@auth\/core['"]/,
  skipCSRFCheckBoolean: /skipCSRFCheck:\s*(true|false)/,
  skipCSRFCheckConditionalSpread: /\.\.\.\(.*skipCSRFCheck.*\)/,
  skipCSRFCheckTernary: /\?\s*\{\s*skipCSRFCheck\s*\}\s*:\s*\{\s*\}/,
  skipCSRFCheckProcessEnv: /skipCSRFCheck:\s*process\.env/,
  nodeEnvDevelopment: /NODE_ENV\s*===\s*['"]development['"]/,
  authCoreImport: /from\s+['"]@auth\/core['"]/,

  // Google OAuth Provider
  googleProvider: /Google\s*\(/,
  googleClientId: /GOOGLE_CLIENT_ID/,
  googleClientSecret: /GOOGLE_CLIENT_SECRET/,
  accessTypeOffline: /access_type:\s*['"]offline['"]/,
  promptConsent: /prompt:\s*['"]consent['"]/,
  scopeOpenId: /['"]openid['"]/,
  scopeEmail: /['"]email['"]/,
  scopeProfile: /['"]profile['"]/,

  // Auth Configuration
  trustHost: /trustHost:\s*true/,
  exportHandlers: /export\s+const\s+\{\s*handlers/,
  exportAuth: /export\s+const\s+\{[^}]*auth[^}]*\}/,
  exportSignIn: /export\s+const\s+\{[^}]*signIn[^}]*\}/,
  exportSignOut: /export\s+const\s+\{[^}]*signOut[^}]*\}/,

  // Route Handler
  importHandlers:
    /import\s+\{[^}]*handlers[^}]*\}\s+from\s+['"]@\/lib\/auth['"]/,
  exportGetPost: /export\s+const\s+\{\s*GET\s*,\s*POST\s*\}/,
} as const;

/** Helper to read file content safely */
function readFileContent(filePath: string): {
  content: string;
  exists: boolean;
} {
  try {
    return { content: fs.readFileSync(filePath, "utf-8"), exists: true };
  } catch {
    return { content: "", exists: false };
  }
}

/** Helper to check if NODE_ENV would enable CSRF skip */
function shouldSkipCSRF(): boolean {
  return process.env.NODE_ENV === "development";
}

// =============================================================================
// Test Suites
// =============================================================================

describe("Google OAuth CSRF Configuration", () => {
  let authFile: { content: string; exists: boolean };

  beforeAll(() => {
    authFile = readFileContent(FILE_PATHS.auth);
  });

  describe("skipCSRFCheck configuration", () => {
    it("should import skipCSRFCheck symbol from @auth/core", () => {
      expect(authFile.content).toMatch(PATTERNS.skipCSRFCheckImport);
    });

    it("should NOT use boolean for skipCSRFCheck (common mistake that causes MissingCSRF)", () => {
      expect(authFile.content).not.toMatch(PATTERNS.skipCSRFCheckBoolean);
    });

    it("should use conditional spread for skipCSRFCheck symbol", () => {
      expect(authFile.content).toMatch(PATTERNS.skipCSRFCheckConditionalSpread);
    });

    it("should only enable skipCSRFCheck in development mode", () => {
      expect(authFile.content).toMatch(PATTERNS.nodeEnvDevelopment);
    });

    it("should use ternary operator with empty object for production", () => {
      expect(authFile.content).toMatch(PATTERNS.skipCSRFCheckTernary);
    });
  });

  describe("Auth configuration structure", () => {
    it("should have Google provider configured", () => {
      expect(authFile.content).toMatch(PATTERNS.googleProvider);
      expect(authFile.content).toMatch(PATTERNS.googleClientId);
      expect(authFile.content).toMatch(PATTERNS.googleClientSecret);
    });

    it("should have trustHost enabled for local development", () => {
      expect(authFile.content).toMatch(PATTERNS.trustHost);
    });

    it("should export handlers for API routes", () => {
      expect(authFile.content).toMatch(PATTERNS.exportHandlers);
    });

    it("should export auth function for server-side usage", () => {
      expect(authFile.content).toMatch(PATTERNS.exportAuth);
    });

    it("should export signIn function for client-side usage", () => {
      expect(authFile.content).toMatch(PATTERNS.exportSignIn);
    });

    it("should export signOut function", () => {
      expect(authFile.content).toMatch(PATTERNS.exportSignOut);
    });
  });

  describe("Development vs Production behavior", () => {
    const originalNodeEnv = process.env.NODE_ENV;

    afterEach(() => {
      process.env.NODE_ENV = originalNodeEnv;
    });

    it("should evaluate to skip CSRF in development", () => {
      process.env.NODE_ENV = "development";
      expect(shouldSkipCSRF()).toBe(true);
    });

    it("should NOT skip CSRF in production", () => {
      process.env.NODE_ENV = "production";
      expect(shouldSkipCSRF()).toBe(false);
    });

    it("should NOT skip CSRF in test environment", () => {
      process.env.NODE_ENV = "test";
      expect(shouldSkipCSRF()).toBe(false);
    });
  });
});

describe("Google OAuth Provider Configuration", () => {
  let authFile: { content: string; exists: boolean };

  beforeAll(() => {
    authFile = readFileContent(FILE_PATHS.auth);
  });

  it("should request offline access for refresh tokens", () => {
    expect(authFile.content).toMatch(PATTERNS.accessTypeOffline);
  });

  it("should request consent prompt", () => {
    expect(authFile.content).toMatch(PATTERNS.promptConsent);
  });

  it("should request openid scope", () => {
    expect(authFile.content).toMatch(PATTERNS.scopeOpenId);
  });

  it("should request email scope", () => {
    expect(authFile.content).toMatch(PATTERNS.scopeEmail);
  });

  it("should request profile scope", () => {
    expect(authFile.content).toMatch(PATTERNS.scopeProfile);
  });
});

describe("NextAuth Route Handler", () => {
  let routeFile: { content: string; exists: boolean };

  beforeAll(() => {
    routeFile = readFileContent(FILE_PATHS.nextAuthRoute);
  });

  it("should have the NextAuth route file", () => {
    expect(routeFile.exists).toBe(true);
  });

  it("should import handlers from lib/auth", () => {
    if (!routeFile.exists) {
      console.log("Skipping: Route file not found");
      return;
    }
    expect(routeFile.content).toMatch(PATTERNS.importHandlers);
  });

  it("should export GET and POST handlers", () => {
    if (!routeFile.exists) {
      console.log("Skipping: Route file not found");
      return;
    }
    expect(routeFile.content).toMatch(PATTERNS.exportGetPost);
  });
});

describe("Regression prevention", () => {
  let authFile: { content: string; exists: boolean };

  beforeAll(() => {
    authFile = readFileContent(FILE_PATHS.auth);
  });

  it("should NOT have skipCSRFCheck as a simple boolean property", () => {
    // This was the bug: skipCSRFCheck: process.env.NODE_ENV === 'development'
    // evaluates to a boolean, not the symbol
    expect(authFile.content).not.toMatch(PATTERNS.skipCSRFCheckProcessEnv);
  });

  it("should NOT have skipCSRFCheck hardcoded to true", () => {
    expect(authFile.content).not.toMatch(/skipCSRFCheck:\s*true/);
  });

  it("should NOT have skipCSRFCheck hardcoded to false", () => {
    expect(authFile.content).not.toMatch(/skipCSRFCheck:\s*false/);
  });

  it("should have the correct import from @auth/core", () => {
    expect(authFile.content).toMatch(PATTERNS.authCoreImport);
  });
});
