"use strict";
/**
 * Clerk Authentication Generator
 * Generates Clerk SDK integration for both frontend and backend
 */
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    var desc = Object.getOwnPropertyDescriptor(m, k);
    if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
      desc = { enumerable: true, get: function() { return m[k]; } };
    }
    Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
    if (k2 === undefined) k2 = k;
    o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
    Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
    o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
    var ownKeys = function(o) {
        ownKeys = Object.getOwnPropertyNames || function (o) {
            var ar = [];
            for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
            return ar;
        };
        return ownKeys(o);
    };
    return function (mod) {
        if (mod && mod.__esModule) return mod;
        var result = {};
        if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
        __setModuleDefault(result, mod);
        return result;
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.ClerkAuthGenerator = void 0;
const path = __importStar(require("path"));
class ClerkAuthGenerator {
    id = 'clerk-auth';
    name = 'Clerk Authentication Generator';
    description = 'Generates Clerk authentication integration';
    generate(context, config = {}) {
        const { outputDirectory } = context;
        const files = [];
        // Generate backend files
        files.push(...this.generateBackendFiles(outputDirectory, config));
        // Generate frontend files
        files.push(...this.generateFrontendFiles(outputDirectory, config));
        return {
            files,
            dependencies: {
                backend: this.getBackendDependencies(),
                frontend: this.getFrontendDependencies(),
            },
        };
    }
    /**
     * Generate backend Clerk integration
     */
    generateBackendFiles(outputDir, _config) {
        const files = [];
        // 1. Clerk middleware
        files.push(this.generateClerkMiddleware(outputDir));
        // 2. TypeScript types
        files.push(this.generateBackendTypes(outputDir));
        // 3. Update package.json dependencies
        // Note: This would be handled by the main generator orchestrator
        return files;
    }
    /**
     * Generate Clerk Express middleware
     */
    generateClerkMiddleware(outputDir) {
        const code = `import { clerkMiddleware, requireAuth, getAuth } from '@clerk/express';
import { Request, Response, NextFunction } from 'express';

/**
 * Clerk middleware - adds auth object to request
 * Use this for routes that can be accessed by both authenticated and unauthenticated users
 */
export const clerkAuth = clerkMiddleware();

/**
 * Require authentication middleware
 * Protects routes by requiring users to be signed in
 */
export const authenticate = requireAuth();

/**
 * Role-based authorization middleware
 * Checks if the authenticated user has one of the required roles
 */
export const authorize = (allowedRoles: string[]) => {
  return (req: Request, res: Response, next: NextFunction) => {
    const auth = getAuth(req);

    if (!auth.userId) {
      return res.status(401).json({ message: 'Not authenticated' });
    }

    // Get user roles from Clerk metadata
    const userRoles = (auth.sessionClaims?.metadata as any)?.roles || [];

    if (!allowedRoles.some(role => userRoles.includes(role))) {
      return res.status(403).json({ message: 'Insufficient permissions' });
    }

    next();
  };
};

/**
 * Get current user ID from request
 */
export const getCurrentUserId = (req: Request): string | null => {
  const auth = getAuth(req);
  return auth.userId || null;
};

/**
 * Error handler for Clerk errors
 */
export const clerkErrorHandler = (error: Error, req: Request, res: Response, next: NextFunction) => {
  console.error('Clerk error:', error);
  res.status(500).json({ message: 'Authentication error' });
};
`;
        return {
            path: path.join(outputDir, 'backend', 'src', 'middleware', 'clerk-auth.ts'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate TypeScript types for Clerk
     */
    generateBackendTypes(outputDir) {
        const code = `/// <reference types="@clerk/express/env" />

declare global {
  namespace Express {
    interface Request {
      auth: {
        userId: string | null;
        sessionId: string | null;
        orgId: string | null;
        sessionClaims: any;
      };
    }
  }
}

export {};
`;
        return {
            path: path.join(outputDir, 'backend', 'types', 'clerk.d.ts'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate frontend Clerk integration
     */
    generateFrontendFiles(outputDir, config) {
        const files = [];
        // 1. Clerk Provider wrapper
        files.push(this.generateClerkProvider(outputDir, config));
        // 2. Login page
        files.push(this.generateLoginPage(outputDir, config));
        // 3. Signup page
        files.push(this.generateSignupPage(outputDir, config));
        // 4. Auth hooks
        files.push(this.generateAuthHooks(outputDir));
        // 5. Protected Route component
        files.push(this.generateProtectedRoute(outputDir));
        return files;
    }
    /**
     * Generate Clerk Provider wrapper
     */
    generateClerkProvider(outputDir, config) {
        const code = `import React from 'react';
import { ClerkProvider } from '@clerk/clerk-react';

interface AuthProviderProps {
  children: React.ReactNode;
}

export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
  const publishableKey = import.meta.env.VITE_CLERK_PUBLISHABLE_KEY;

  if (!publishableKey) {
    throw new Error('Missing Clerk Publishable Key');
  }

  return (
    <ClerkProvider
      publishableKey={publishableKey}
      afterSignInUrl="${config.afterSignInUrl || '/'}"
      afterSignUpUrl="${config.afterSignUpUrl || '/'}"
    >
      {children}
    </ClerkProvider>
  );
};
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'components', 'AuthProvider.tsx'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate Login page
     */
    generateLoginPage(outputDir, _config) {
        const code = `import React from 'react';
import { SignIn } from '@clerk/clerk-react';

export const Login: React.FC = () => {
  return (
    <div className="flex items-center justify-center min-h-screen bg-gray-50">
      <div className="w-full max-w-md">
        <SignIn
          routing="path"
          path="/login"
          signUpUrl="/signup"
        />
      </div>
    </div>
  );
};
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'pages', 'Login.tsx'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate Signup page
     */
    generateSignupPage(outputDir, _config) {
        const code = `import React from 'react';
import { SignUp } from '@clerk/clerk-react';

export const Signup: React.FC = () => {
  return (
    <div className="flex items-center justify-center min-h-screen bg-gray-50">
      <div className="w-full max-w-md">
        <SignUp
          routing="path"
          path="/signup"
          signInUrl="/login"
        />
      </div>
    </div>
  );
};
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'pages', 'Signup.tsx'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate auth hooks
     */
    generateAuthHooks(outputDir) {
        const code = `import { useUser, useAuth, useClerk } from '@clerk/clerk-react';

/**
 * Hook to get current user
 */
export const useCurrentUser = () => {
  const { user, isLoaded, isSignedIn } = useUser();

  return {
    user,
    isLoaded,
    isSignedIn,
  };
};

/**
 * Hook to get auth functions
 */
export const useAuthFunctions = () => {
  const { signOut } = useClerk();
  const { getToken } = useAuth();

  return {
    signOut,
    getToken,
  };
};

/**
 * Hook to check if user has a specific role
 */
export const useHasRole = (role: string): boolean => {
  const { user } = useUser();
  const roles = (user?.publicMetadata?.roles as string[]) || [];
  return roles.includes(role);
};
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'hooks', 'useAuth.ts'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate Protected Route component
     */
    generateProtectedRoute(outputDir) {
        const code = `import React from 'react';
import { useAuth } from '@clerk/clerk-react';
import { Navigate } from 'react-router-dom';

interface ProtectedRouteProps {
  children: React.ReactNode;
  requiredRoles?: string[];
}

export const ProtectedRoute: React.FC<ProtectedRouteProps> = ({
  children,
  requiredRoles = []
}) => {
  const { isSignedIn, isLoaded, userId } = useAuth();

  // Show loading state while auth is initializing
  if (!isLoaded) {
    return <div className="flex items-center justify-center min-h-screen">Loading...</div>;
  }

  // Redirect to login if not signed in
  if (!isSignedIn) {
    return <Navigate to="/login" replace />;
  }

  // TODO: Add role checking when needed
  // if (requiredRoles.length > 0) {
  //   const userRoles = user?.publicMetadata?.roles || [];
  //   if (!requiredRoles.some(role => userRoles.includes(role))) {
  //     return <Navigate to="/unauthorized" replace />;
  //   }
  // }

  return <>{children}</>;
};
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'components', 'ProtectedRoute.tsx'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate environment variable template
     */
    generateEnvTemplate() {
        return `# Clerk Authentication
CLERK_SECRET_KEY=your_clerk_secret_key_here
VITE_CLERK_PUBLISHABLE_KEY=your_clerk_publishable_key_here
`;
    }
    /**
     * Get required npm dependencies for backend
     */
    getBackendDependencies() {
        return {
            '@clerk/express': '^1.7.37',
        };
    }
    /**
     * Get required npm dependencies for frontend
     */
    getFrontendDependencies() {
        return {
            '@clerk/clerk-react': '^5.0.0',
        };
    }
}
exports.ClerkAuthGenerator = ClerkAuthGenerator;
//# sourceMappingURL=clerk-generator.js.map