/**
 * Auth0 Management API Client
 * Provides methods for user management operations via Auth0 Management API
 */
import { ManagementClient } from 'auth0';
import { appConfig } from '../config/config-loader';
import { logger } from '../logging/logger';

interface CreateUserParams {
  email: string;
  password: string;
  emailVerified?: boolean; // Optional: set true for trusted users (e.g., CLI-created admins)
}

interface UserDetails {
  userId: string;
  email: string;
  emailVerified: boolean;
}

class Auth0ManagementClientSingleton {
  private client: ManagementClient | null = null;
  private readonly CONNECTION_NAME = 'Username-Password-Authentication';

  /**
   * Lazy initialization of ManagementClient to avoid startup issues
   */
  private getClient(): ManagementClient {
    if (!this.client) {
      const config = appConfig.getAuth0ManagementConfig();

      this.client = new ManagementClient({
        domain: config.domain,
        clientId: config.clientId,
        clientSecret: config.clientSecret,
      });

      logger.info('Auth0 Management API client initialized');
    }

    return this.client;
  }

  /**
   * Create a new user in Auth0
   * @param email User's email address
   * @param password User's password
   * @returns Auth0 user ID
   */
  async createUser({ email, password, emailVerified = false }: CreateUserParams): Promise<string> {
    try {
      const client = this.getClient();

      const response = await client.users.create({
        connection: this.CONNECTION_NAME,
        email,
        password,
        email_verified: emailVerified,
      });

      const user = response.data;
      if (!user.user_id) {
        throw new Error('Auth0 did not return a user_id');
      }

      logger.info('User created in Auth0', { userId: user.user_id, email });
      return user.user_id;
    } catch (error) {
      logger.error('Failed to create user in Auth0', { email, error });
      throw new Error(`Auth0 user creation failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * Get user details from Auth0
   * @param userId Auth0 user ID (format: auth0|xxx or google-oauth2|xxx)
   * @returns User details including email and verification status
   */
  async getUser(userId: string): Promise<UserDetails> {
    try {
      const client = this.getClient();

      const response = await client.users.get({ id: userId });
      const user = response.data;

      if (!user.email) {
        throw new Error('User email not found in Auth0 response');
      }

      logger.info('Retrieved user from Auth0', { userId, email: user.email });

      return {
        userId: user.user_id || userId,
        email: user.email,
        emailVerified: user.email_verified || false,
      };
    } catch (error) {
      logger.error('Failed to get user from Auth0', { userId, error });
      throw new Error(`Auth0 user retrieval failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * Resend email verification to user
   * @param userId Auth0 user ID
   */
  async resendVerificationEmail(userId: string): Promise<void> {
    try {
      const client = this.getClient();

      await client.jobs.verifyEmail({
        user_id: userId,
      });

      logger.info('Verification email sent', { userId });
    } catch (error) {
      logger.error('Failed to send verification email', { userId, error });
      throw new Error(`Failed to send verification email: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * Check if user's email is verified
   * @param userId Auth0 user ID
   * @returns true if email is verified, false otherwise
   */
  async checkEmailVerified(userId: string): Promise<boolean> {
    try {
      const user = await this.getUser(userId);
      return user.emailVerified;
    } catch (error) {
      logger.error('Failed to check email verification status', { userId, error });
      throw new Error(`Failed to check email verification: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * Delete a user from Auth0 (permanent deletion)
   * @param userId Auth0 user ID (format: auth0|xxx or google-oauth2|xxx)
   */
  async deleteUser(userId: string): Promise<void> {
    try {
      const client = this.getClient();

      await client.users.delete({ id: userId });

      logger.info('User deleted from Auth0', { userId });
    } catch (error) {
      logger.error('Failed to delete user from Auth0', { userId, error });
      throw new Error(`Auth0 user deletion failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * Send password reset email to user
   * Uses Auth0 Authentication API (not Management API)
   * @param email User's email address
   */
  async sendPasswordResetEmail(email: string): Promise<void> {
    try {
      const config = appConfig.getAuth0ManagementConfig();

      const response = await fetch(`https://${config.domain}/dbconnections/change_password`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          client_id: config.clientId,
          email,
          connection: this.CONNECTION_NAME,
        }),
      });

      if (!response.ok) {
        const errorBody = await response.text();
        logger.error('Password reset email request failed', { email: email.substring(0, 3) + '***', status: response.status, error: errorBody });
        throw new Error(`Password reset email failed: ${response.status}`);
      }

      logger.info('Password reset email sent', { email: email.substring(0, 3) + '***' });
    } catch (error) {
      logger.error('Failed to send password reset email', { email: email.substring(0, 3) + '***', error });
      throw new Error(`Failed to send password reset email: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }

  /**
   * Verify user password using Resource Owner Password Grant
   * @param email User's email address
   * @param password User's password to verify
   * @returns true if password is valid, false otherwise
   */
  async verifyPassword(email: string, password: string): Promise<boolean> {
    try {
      const config = appConfig.getAuth0ManagementConfig();

      const response = await fetch(`https://${config.domain}/oauth/token`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
        },
        body: JSON.stringify({
          grant_type: 'password',
          username: email,
          password,
          client_id: config.clientId,
          client_secret: config.clientSecret,
          audience: `https://${config.domain}/api/v2/`,
          scope: 'openid profile email',
        }),
      });

      if (response.ok) {
        logger.info('Password verification successful', { email });
        return true;
      }

      if (response.status === 403 || response.status === 401) {
        logger.info('Password verification failed - invalid credentials', { email });
        return false;
      }

      const errorBody = await response.text();
      logger.error('Password verification request failed', { email, status: response.status, error: errorBody });
      throw new Error(`Password verification failed with status ${response.status}`);
    } catch (error) {
      logger.error('Failed to verify password', { email, error });
      throw new Error(`Password verification failed: ${error instanceof Error ? error.message : 'Unknown error'}`);
    }
  }
}

// Export singleton instance
export const auth0ManagementClient = new Auth0ManagementClientSingleton();
