/**
 * @ai-summary Auth service business logic
 * @ai-context Coordinates between Auth0 Management API and local user profile database
 */

import { auth0ManagementClient } from '../../../core/auth/auth0-management.client';
import { UserProfileRepository } from '../../user-profile/data/user-profile.repository';
import { TermsAgreementRepository } from '../../terms-agreement/data/terms-agreement.repository';
import { pool } from '../../../core/config/database';
import { logger } from '../../../core/logging/logger';
import {
  SignupRequest,
  SignupResponse,
  VerifyStatusResponse,
  ResendVerificationResponse,
  SecurityStatusResponse,
  PasswordResetResponse,
  TermsData,
} from './auth.types';

export class AuthService {
  constructor(
    private userProfileRepository: UserProfileRepository,
    private termsAgreementRepository: TermsAgreementRepository
  ) {}

  /**
   * Create a new user account
   * 1. Create user in Auth0 (which automatically sends verification email)
   * 2. Create local user profile and terms agreement atomically
   */
  async signup(request: SignupRequest, termsData: TermsData): Promise<SignupResponse> {
    const { email, password } = request;

    try {
      // Create user in Auth0 Management API
      // Auth0 automatically sends verification email on user creation
      const auth0UserId = await auth0ManagementClient.createUser({
        email,
        password,
      });

      logger.info('Auth0 user created', { auth0UserId, email });

      // Create local user profile and terms agreement in a transaction
      const client = await pool.connect();
      try {
        await client.query('BEGIN');

        // Create user profile
        const profileQuery = `
          INSERT INTO user_profiles (auth0_sub, email, subscription_tier)
          VALUES ($1, $2, 'free')
          RETURNING id
        `;
        const profileResult = await client.query(profileQuery, [auth0UserId, email]);
        const profileId = profileResult.rows[0].id;

        logger.info('User profile created', { userId: profileId, email });

        // Create terms agreement
        await this.termsAgreementRepository.create({
          userId: auth0UserId,
          ipAddress: termsData.ipAddress,
          userAgent: termsData.userAgent,
          termsVersion: termsData.termsVersion,
          termsUrl: termsData.termsUrl,
          termsContentHash: termsData.termsContentHash,
        }, client);

        logger.info('Terms agreement created', { userId: auth0UserId });

        await client.query('COMMIT');
      } catch (error) {
        await client.query('ROLLBACK');
        logger.error('Transaction failed, rolling back', { error, email });
        throw error;
      } finally {
        client.release();
      }

      return {
        userId: auth0UserId,
        email,
        message: 'Account created successfully. Please check your email to verify your account.',
      };
    } catch (error) {
      logger.error('Signup failed', { email, error });

      // Check for duplicate email error from Auth0
      if (error instanceof Error && error.message.includes('already exists')) {
        throw new Error('Email already exists');
      }

      throw error;
    }
  }

  /**
   * Check email verification status
   * Queries Auth0 for current verification status and updates local database if changed
   */
  async getVerifyStatus(auth0Sub: string): Promise<VerifyStatusResponse> {
    try {
      // Get user details from Auth0
      const userDetails = await auth0ManagementClient.getUser(auth0Sub);

      logger.info('Retrieved user verification status from Auth0', {
        auth0Sub,
        emailVerified: userDetails.emailVerified,
      });

      // Update local database if verification status changed
      const localProfile = await this.userProfileRepository.getByAuth0Sub(auth0Sub);

      if (localProfile && localProfile.emailVerified !== userDetails.emailVerified) {
        await this.userProfileRepository.updateEmailVerified(
          auth0Sub,
          userDetails.emailVerified
        );
        logger.info('Local email verification status updated', {
          auth0Sub,
          emailVerified: userDetails.emailVerified,
        });
      }

      return {
        emailVerified: userDetails.emailVerified,
        email: userDetails.email,
      };
    } catch (error) {
      logger.error('Failed to get verification status', { auth0Sub, error });
      throw error;
    }
  }

  /**
   * Resend verification email
   * Calls Auth0 Management API to trigger verification email
   */
  async resendVerification(auth0Sub: string): Promise<ResendVerificationResponse> {
    try {
      // Check if already verified
      const verified = await auth0ManagementClient.checkEmailVerified(auth0Sub);

      if (verified) {
        logger.info('Email already verified, skipping resend', { auth0Sub });
        return {
          message: 'Email is already verified',
        };
      }

      // Request Auth0 to resend verification email
      await auth0ManagementClient.resendVerificationEmail(auth0Sub);

      logger.info('Verification email resent', { auth0Sub });

      return {
        message: 'Verification email sent. Please check your inbox.',
      };
    } catch (error) {
      logger.error('Failed to resend verification email', { auth0Sub, error });
      throw error;
    }
  }

  /**
   * Resend verification email by email address (public endpoint)
   * Looks up user by email and sends verification if not verified
   */
  async resendVerificationByEmail(email: string): Promise<ResendVerificationResponse> {
    try {
      // Look up user by email in our database
      const userProfile = await this.userProfileRepository.getByEmail(email);

      if (!userProfile) {
        // Don't reveal if email exists - return success message regardless
        logger.info('Resend verification requested for unknown email', {
          email: email.substring(0, 3) + '***',
        });
        return {
          message: 'If an account exists with this email, a verification link will be sent.',
        };
      }

      // Check if already verified via Auth0
      const verified = await auth0ManagementClient.checkEmailVerified(userProfile.auth0Sub);

      if (verified) {
        logger.info('Email already verified, skipping resend', { email: email.substring(0, 3) + '***' });
        return {
          message: 'If an account exists with this email, a verification link will be sent.',
        };
      }

      // Request Auth0 to resend verification email
      await auth0ManagementClient.resendVerificationEmail(userProfile.auth0Sub);

      logger.info('Verification email resent via public endpoint', {
        email: email.substring(0, 3) + '***',
      });

      return {
        message: 'If an account exists with this email, a verification link will be sent.',
      };
    } catch (error) {
      logger.error('Failed to resend verification email by email', {
        email: email.substring(0, 3) + '***',
        error,
      });
      // Don't reveal error details - return generic success for security
      return {
        message: 'If an account exists with this email, a verification link will be sent.',
      };
    }
  }

  /**
   * Get user status for routing decisions
   * Returns email verification and onboarding completion status
   */
  async getUserStatus(auth0Sub: string): Promise<{
    emailVerified: boolean;
    onboardingCompleted: boolean;
    email: string;
  }> {
    try {
      // Get user details from Auth0
      const auth0User = await auth0ManagementClient.getUser(auth0Sub);

      // Get local profile for onboarding status
      const localProfile = await this.userProfileRepository.getByAuth0Sub(auth0Sub);

      // Sync email verification status if needed
      if (localProfile && localProfile.emailVerified !== auth0User.emailVerified) {
        await this.userProfileRepository.updateEmailVerified(auth0Sub, auth0User.emailVerified);
      }

      return {
        emailVerified: auth0User.emailVerified,
        onboardingCompleted: localProfile?.onboardingCompletedAt !== null,
        email: auth0User.email,
      };
    } catch (error) {
      logger.error('Failed to get user status', { auth0Sub, error });
      throw error;
    }
  }

  /**
   * Get security status for the user
   * Returns email verification status and passkey info
   */
  async getSecurityStatus(auth0Sub: string): Promise<SecurityStatusResponse> {
    try {
      // Get user details from Auth0
      const auth0User = await auth0ManagementClient.getUser(auth0Sub);

      logger.info('Retrieved security status', {
        auth0Sub: auth0Sub.substring(0, 8) + '...',
        emailVerified: auth0User.emailVerified,
      });

      return {
        emailVerified: auth0User.emailVerified,
        email: auth0User.email,
        // Passkeys are enabled at the Auth0 connection level, not per-user
        // This is informational - actual passkey enrollment happens in Auth0 Universal Login
        passkeysEnabled: true,
        // Auth0 doesn't expose password last changed date via Management API
        // Would require Auth0 Logs API or user_metadata to track this
        passwordLastChanged: null,
      };
    } catch (error) {
      logger.error('Failed to get security status', { auth0Sub, error });
      throw error;
    }
  }

  /**
   * Request password reset email
   * Triggers Auth0 to send password reset email to user
   */
  async requestPasswordReset(auth0Sub: string): Promise<PasswordResetResponse> {
    try {
      // Get user email from Auth0
      const auth0User = await auth0ManagementClient.getUser(auth0Sub);

      // Send password reset email via Auth0
      await auth0ManagementClient.sendPasswordResetEmail(auth0User.email);

      logger.info('Password reset email requested', {
        auth0Sub: auth0Sub.substring(0, 8) + '...',
        email: auth0User.email.substring(0, 3) + '***',
      });

      return {
        message: 'Password reset email sent. Please check your inbox.',
        success: true,
      };
    } catch (error) {
      logger.error('Failed to request password reset', { auth0Sub, error });
      throw error;
    }
  }
}
