"use strict";
/**
 * Supabase Authentication Generator
 * Generates Supabase 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.SupabaseAuthGenerator = void 0;
const path = __importStar(require("path"));
class SupabaseAuthGenerator {
    id = 'supabase-auth';
    name = 'Supabase Authentication Generator';
    description = 'Generates Supabase 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 Supabase integration
     */
    generateBackendFiles(outputDir, _config) {
        const files = [];
        // 1. Supabase client setup
        files.push(this.generateSupabaseClient(outputDir));
        // 2. Supabase middleware
        files.push(this.generateSupabaseMiddleware(outputDir));
        // 3. TypeScript types
        files.push(this.generateBackendTypes(outputDir));
        return files;
    }
    /**
     * Generate Supabase client configuration
     */
    generateSupabaseClient(outputDir) {
        const code = `import { createClient, SupabaseClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.SUPABASE_URL;
const supabaseServiceKey = process.env.SUPABASE_SERVICE_ROLE_KEY;

if (!supabaseUrl || !supabaseServiceKey) {
  throw new Error(
    'Missing Supabase configuration. Please set SUPABASE_URL and SUPABASE_SERVICE_ROLE_KEY'
  );
}

/**
 * Supabase admin client for backend operations
 * Uses service role key to bypass RLS policies
 */
export const supabaseAdmin: SupabaseClient = createClient(
  supabaseUrl,
  supabaseServiceKey,
  {
    auth: {
      autoRefreshToken: false,
      persistSession: false,
    },
  }
);

/**
 * Create a Supabase client for a specific user
 * Used for operations that should respect Row Level Security
 */
export const createUserClient = (accessToken: string): SupabaseClient => {
  if (!supabaseUrl) {
    throw new Error('Missing SUPABASE_URL');
  }

  return createClient(supabaseUrl, process.env.SUPABASE_ANON_KEY || '', {
    global: {
      headers: {
        Authorization: \`Bearer \${accessToken}\`,
      },
    },
    auth: {
      persistSession: false,
    },
  });
};
`;
        return {
            path: path.join(outputDir, 'backend', 'src', 'lib', 'supabase.ts'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate Supabase Express middleware
     */
    generateSupabaseMiddleware(outputDir) {
        const code = `import { Request, Response, NextFunction } from 'express';
import { supabaseAdmin, createUserClient } from '../lib/supabase';

/**
 * Supabase authentication middleware
 * Validates JWT tokens from Supabase Auth
 */
export const supabaseAuth = async (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  try {
    const authHeader = req.headers.authorization;

    if (!authHeader || !authHeader.startsWith('Bearer ')) {
      req.supabase = { user: null, client: null };
      return next();
    }

    const token = authHeader.substring(7);

    // Verify the JWT
    const { data: { user }, error } = await supabaseAdmin.auth.getUser(token);

    if (error || !user) {
      req.supabase = { user: null, client: null };
      return next();
    }

    // Attach user and client to request
    req.supabase = {
      user,
      client: createUserClient(token),
    };

    next();
  } catch (error) {
    console.error('Supabase auth error:', error);
    req.supabase = { user: null, client: null };
    next();
  }
};

/**
 * Require authentication middleware
 * Ensures the request has a valid authenticated user
 */
export const requireAuth = (
  req: Request,
  res: Response,
  next: NextFunction
) => {
  if (!req.supabase?.user) {
    return res.status(401).json({ message: 'Authentication required' });
  }
  next();
};

/**
 * Role-based authorization middleware
 * Checks if the authenticated user has one of the required roles
 */
export const authorize = (allowedRoles: string[]) => {
  return async (req: Request, res: Response, next: NextFunction) => {
    if (!req.supabase?.user) {
      return res.status(401).json({ message: 'Not authenticated' });
    }

    const userId = req.supabase.user.id;

    // Get user roles from user_metadata or app_metadata
    const userRoles = (req.supabase.user.user_metadata?.roles as string[]) ||
                     (req.supabase.user.app_metadata?.roles as string[]) || [];

    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 => {
  return req.supabase?.user?.id || null;
};

/**
 * Error handler for Supabase errors
 */
export const supabaseErrorHandler = (
  error: Error,
  req: Request,
  res: Response,
  next: NextFunction
) => {
  console.error('Supabase error:', error);
  res.status(500).json({ message: 'Authentication error' });
};
`;
        return {
            path: path.join(outputDir, 'backend', 'src', 'middleware', 'supabase-auth.ts'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate TypeScript types for Supabase
     */
    generateBackendTypes(outputDir) {
        const code = `import { User, SupabaseClient } from '@supabase/supabase-js';

declare global {
  namespace Express {
    interface Request {
      supabase?: {
        user: User | null;
        client: SupabaseClient | null;
      };
    }
  }
}

export {};
`;
        return {
            path: path.join(outputDir, 'backend', 'types', 'supabase.d.ts'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate frontend Supabase integration
     */
    generateFrontendFiles(outputDir, config) {
        const files = [];
        // 1. Supabase client setup
        files.push(this.generateFrontendClient(outputDir));
        // 2. Auth Provider
        files.push(this.generateAuthProvider(outputDir, config));
        // 3. Login page
        files.push(this.generateLoginPage(outputDir));
        // 4. Signup page
        files.push(this.generateSignupPage(outputDir));
        // 5. Auth hooks
        files.push(this.generateAuthHooks(outputDir));
        // 6. Protected Route component
        files.push(this.generateProtectedRoute(outputDir));
        return files;
    }
    /**
     * Generate Supabase client for frontend
     */
    generateFrontendClient(outputDir) {
        const code = `import { createClient } from '@supabase/supabase-js';

const supabaseUrl = import.meta.env.VITE_SUPABASE_URL;
const supabaseAnonKey = import.meta.env.VITE_SUPABASE_ANON_KEY;

if (!supabaseUrl || !supabaseAnonKey) {
  throw new Error(
    'Missing Supabase configuration. Please set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY'
  );
}

export const supabase = createClient(supabaseUrl, supabaseAnonKey, {
  auth: {
    autoRefreshToken: true,
    persistSession: true,
    detectSessionInUrl: true,
  },
});
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'lib', 'supabase.ts'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate Auth Provider
     */
    generateAuthProvider(outputDir, _config) {
        const code = `import React, { createContext, useContext, useEffect, useState } from 'react';
import { User, Session } from '@supabase/supabase-js';
import { supabase } from '../lib/supabase';

interface AuthContextType {
  user: User | null;
  session: Session | null;
  isLoading: boolean;
}

const AuthContext = createContext<AuthContextType>({
  user: null,
  session: null,
  isLoading: true,
});

interface AuthProviderProps {
  children: React.ReactNode;
}

export const AuthProvider: React.FC<AuthProviderProps> = ({ children }) => {
  const [user, setUser] = useState<User | null>(null);
  const [session, setSession] = useState<Session | null>(null);
  const [isLoading, setIsLoading] = useState(true);

  useEffect(() => {
    // Get initial session
    supabase.auth.getSession().then(({ data: { session } }) => {
      setSession(session);
      setUser(session?.user ?? null);
      setIsLoading(false);
    });

    // Listen for auth changes
    const {
      data: { subscription },
    } = supabase.auth.onAuthStateChange((_event, session) => {
      setSession(session);
      setUser(session?.user ?? null);
      setIsLoading(false);
    });

    return () => subscription.unsubscribe();
  }, []);

  return (
    <AuthContext.Provider value={{ user, session, isLoading }}>
      {children}
    </AuthContext.Provider>
  );
};

export const useAuth = () => {
  const context = useContext(AuthContext);
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider');
  }
  return context;
};
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'components', 'AuthProvider.tsx'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate Login page
     */
    generateLoginPage(outputDir) {
        const code = `import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { supabase } from '../lib/supabase';

export const Login: React.FC = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const navigate = useNavigate();

  const handleLogin = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError(null);

    try {
      const { error } = await supabase.auth.signInWithPassword({
        email,
        password,
      });

      if (error) throw error;

      navigate('/');
    } catch (error: any) {
      setError(error.message || 'Failed to sign in');
    } finally {
      setLoading(false);
    }
  };

  const handleGoogleLogin = async () => {
    try {
      const { error } = await supabase.auth.signInWithOAuth({
        provider: 'google',
        options: {
          redirectTo: window.location.origin,
        },
      });

      if (error) throw error;
    } catch (error: any) {
      setError(error.message || 'Failed to sign in with Google');
    }
  };

  return (
    <div className="flex items-center justify-center min-h-screen bg-gray-50">
      <div className="w-full max-w-md p-8 space-y-6 bg-white rounded-lg shadow-md">
        <div className="text-center">
          <h1 className="text-3xl font-bold text-gray-900">Welcome Back</h1>
          <p className="mt-2 text-gray-600">Sign in to your account</p>
        </div>

        {error && (
          <div className="p-3 text-sm text-red-600 bg-red-50 rounded-lg">
            {error}
          </div>
        )}

        <form onSubmit={handleLogin} className="space-y-4">
          <div>
            <label htmlFor="email" className="block text-sm font-medium text-gray-700">
              Email
            </label>
            <input
              id="email"
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
              className="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
              placeholder="you@example.com"
            />
          </div>

          <div>
            <label htmlFor="password" className="block text-sm font-medium text-gray-700">
              Password
            </label>
            <input
              id="password"
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
              className="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
              placeholder="••••••••"
            />
          </div>

          <button
            type="submit"
            disabled={loading}
            className="w-full px-4 py-3 text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
          >
            {loading ? 'Signing in...' : 'Sign In'}
          </button>
        </form>

        <div className="relative">
          <div className="absolute inset-0 flex items-center">
            <div className="w-full border-t border-gray-300"></div>
          </div>
          <div className="relative flex justify-center text-sm">
            <span className="px-2 text-gray-500 bg-white">Or continue with</span>
          </div>
        </div>

        <button
          onClick={handleGoogleLogin}
          className="w-full px-4 py-3 text-gray-700 bg-white border border-gray-300 rounded-lg hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors"
        >
          Sign in with Google
        </button>

        <p className="text-sm text-center text-gray-600">
          Don't have an account?{' '}
          <a href="/signup" className="text-blue-600 hover:underline">
            Sign up
          </a>
        </p>
      </div>
    </div>
  );
};
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'pages', 'Login.tsx'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate Signup page
     */
    generateSignupPage(outputDir) {
        const code = `import React, { useState } from 'react';
import { useNavigate } from 'react-router-dom';
import { supabase } from '../lib/supabase';

export const Signup: React.FC = () => {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [confirmPassword, setConfirmPassword] = useState('');
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [success, setSuccess] = useState(false);
  const navigate = useNavigate();

  const handleSignup = async (e: React.FormEvent) => {
    e.preventDefault();
    setLoading(true);
    setError(null);

    if (password !== confirmPassword) {
      setError('Passwords do not match');
      setLoading(false);
      return;
    }

    try {
      const { error } = await supabase.auth.signUp({
        email,
        password,
        options: {
          emailRedirectTo: window.location.origin,
        },
      });

      if (error) throw error;

      setSuccess(true);
      setTimeout(() => navigate('/login'), 3000);
    } catch (error: any) {
      setError(error.message || 'Failed to sign up');
    } finally {
      setLoading(false);
    }
  };

  if (success) {
    return (
      <div className="flex items-center justify-center min-h-screen bg-gray-50">
        <div className="w-full max-w-md p-8 space-y-4 bg-white rounded-lg shadow-md text-center">
          <div className="text-green-600 text-5xl">✓</div>
          <h2 className="text-2xl font-bold text-gray-900">Check your email!</h2>
          <p className="text-gray-600">
            We've sent you a confirmation email. Please check your inbox and click the
            link to verify your account.
          </p>
          <p className="text-sm text-gray-500">Redirecting to login...</p>
        </div>
      </div>
    );
  }

  return (
    <div className="flex items-center justify-center min-h-screen bg-gray-50">
      <div className="w-full max-w-md p-8 space-y-6 bg-white rounded-lg shadow-md">
        <div className="text-center">
          <h1 className="text-3xl font-bold text-gray-900">Create Account</h1>
          <p className="mt-2 text-gray-600">Sign up for a new account</p>
        </div>

        {error && (
          <div className="p-3 text-sm text-red-600 bg-red-50 rounded-lg">
            {error}
          </div>
        )}

        <form onSubmit={handleSignup} className="space-y-4">
          <div>
            <label htmlFor="email" className="block text-sm font-medium text-gray-700">
              Email
            </label>
            <input
              id="email"
              type="email"
              value={email}
              onChange={(e) => setEmail(e.target.value)}
              required
              className="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
              placeholder="you@example.com"
            />
          </div>

          <div>
            <label htmlFor="password" className="block text-sm font-medium text-gray-700">
              Password
            </label>
            <input
              id="password"
              type="password"
              value={password}
              onChange={(e) => setPassword(e.target.value)}
              required
              minLength={6}
              className="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
              placeholder="••••••••"
            />
          </div>

          <div>
            <label htmlFor="confirmPassword" className="block text-sm font-medium text-gray-700">
              Confirm Password
            </label>
            <input
              id="confirmPassword"
              type="password"
              value={confirmPassword}
              onChange={(e) => setConfirmPassword(e.target.value)}
              required
              minLength={6}
              className="w-full px-3 py-2 mt-1 border border-gray-300 rounded-lg focus:outline-none focus:ring-2 focus:ring-blue-500"
              placeholder="••••••••"
            />
          </div>

          <button
            type="submit"
            disabled={loading}
            className="w-full px-4 py-3 text-white bg-blue-600 rounded-lg hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 disabled:opacity-50 disabled:cursor-not-allowed transition-colors"
          >
            {loading ? 'Creating account...' : 'Sign Up'}
          </button>
        </form>

        <p className="text-sm text-center text-gray-600">
          Already have an account?{' '}
          <a href="/login" className="text-blue-600 hover:underline">
            Sign in
          </a>
        </p>
      </div>
    </div>
  );
};
`;
        return {
            path: path.join(outputDir, 'frontend', 'src', 'pages', 'Signup.tsx'),
            content: code,
            overwrite: true,
        };
    }
    /**
     * Generate auth hooks
     */
    generateAuthHooks(outputDir) {
        const code = `import { supabase } from '../lib/supabase';
import { useAuth } from '../components/AuthProvider';

/**
 * Hook to get current user
 */
export const useCurrentUser = () => {
  const { user, isLoading } = useAuth();

  return {
    user,
    isLoaded: !isLoading,
    isSignedIn: !!user,
  };
};

/**
 * Hook to get auth functions
 */
export const useAuthFunctions = () => {
  const signOut = async () => {
    await supabase.auth.signOut();
  };

  const getToken = async () => {
    const { data } = await supabase.auth.getSession();
    return data.session?.access_token || null;
  };

  const resetPassword = async (email: string) => {
    const { error } = await supabase.auth.resetPasswordForEmail(email, {
      redirectTo: window.location.origin + '/reset-password',
    });
    if (error) throw error;
  };

  const updatePassword = async (newPassword: string) => {
    const { error } = await supabase.auth.updateUser({
      password: newPassword,
    });
    if (error) throw error;
  };

  return {
    signOut,
    getToken,
    resetPassword,
    updatePassword,
  };
};

/**
 * Hook to check if user has a specific role
 */
export const useHasRole = (role: string): boolean => {
  const { user } = useAuth();
  const roles = (user?.user_metadata?.roles as string[]) ||
               (user?.app_metadata?.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 { Navigate } from 'react-router-dom';
import { useAuth } from '../components/AuthProvider';

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

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

  // Show loading state while auth is initializing
  if (isLoading) {
    return (
      <div className="flex items-center justify-center min-h-screen">
        <div className="text-center">
          <div className="animate-spin rounded-full h-12 w-12 border-b-2 border-blue-600 mx-auto"></div>
          <p className="mt-4 text-gray-600">Loading...</p>
        </div>
      </div>
    );
  }

  // Redirect to login if not authenticated
  if (!user) {
    return <Navigate to="/login" replace />;
  }

  // Check roles if required
  if (requiredRoles.length > 0) {
    const userRoles = (user.user_metadata?.roles as string[]) ||
                     (user.app_metadata?.roles as string[]) || [];
    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 `# Supabase Configuration
# Backend
SUPABASE_URL=https://your-project.supabase.co
SUPABASE_SERVICE_ROLE_KEY=your_service_role_key_here
SUPABASE_ANON_KEY=your_anon_key_here

# Frontend
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your_anon_key_here
`;
    }
    /**
     * Get required npm dependencies for backend
     */
    getBackendDependencies() {
        return {
            '@supabase/supabase-js': '^2.39.0',
        };
    }
    /**
     * Get required npm dependencies for frontend
     */
    getFrontendDependencies() {
        return {
            '@supabase/supabase-js': '^2.39.0',
        };
    }
}
exports.SupabaseAuthGenerator = SupabaseAuthGenerator;
//# sourceMappingURL=supabase-generator.js.map