import { BadRequestException, ConflictException, Inject, Injectable } from "@nestjs/common";
import { ConfigService } from "@nestjs/config";
import { Logger } from "nestjs-pino";
import * as argon2 from "argon2";

import { DistributedLockService } from "@bff/infra/cache/distributed-lock.service.js";

import {
  ACCOUNT_STATUS,
  type AccountStatus,
  type SendVerificationCodeRequest,
  type SendVerificationCodeResponse,
  type VerifyCodeRequest,
  type VerifyCodeResponse,
  type BilingualEligibilityAddress,
  type GuestEligibilityRequest,
  type GuestEligibilityResponse,
  type CompleteAccountRequest,
  type SignupWithEligibilityRequest,
} from "@customer-portal/domain/get-started";

import { EmailService } from "@bff/infra/email/email.service.js";
import { UsersService } from "@bff/modules/users/application/users.service.js";
import { MappingsService } from "@bff/modules/id-mappings/mappings.service.js";
import { AuditService, AuditAction } from "@bff/infra/audit/audit.service.js";
import { SalesforceAccountService } from "@bff/integrations/salesforce/services/salesforce-account.service.js";
import { OpportunityResolutionService } from "@bff/integrations/salesforce/services/opportunity-resolution.service.js";
import { WorkflowCaseManager } from "@bff/modules/shared/workflow/index.js";
import { WhmcsAccountDiscoveryService } from "@bff/integrations/whmcs/services/whmcs-account-discovery.service.js";
import { extractErrorMessage } from "@bff/core/utils/error.util.js";
import { mapPrismaUserToDomain } from "@bff/infra/mappers/index.js";
import type { AuthResultInternal } from "@bff/modules/auth/auth.types.js";

import { OtpService } from "../otp/otp.service.js";
import { GetStartedSessionService } from "../otp/get-started-session.service.js";
import { AuthTokenService } from "../token/token.service.js";
import { SignupWhmcsService } from "./signup/signup-whmcs.service.js";
import { SignupUserCreationService } from "./signup/signup-user-creation.service.js";
import {
  PORTAL_SOURCE_NEW_SIGNUP,
  PORTAL_SOURCE_INTERNET_ELIGIBILITY,
  PORTAL_STATUS_ACTIVE,
  PORTAL_STATUS_NOT_YET,
} from "@bff/modules/auth/constants/portal.constants.js";
import { SalesforceFacade } from "@bff/integrations/salesforce/facades/salesforce.facade.js";

/**
 * Remove undefined properties from an object (for exactOptionalPropertyTypes compatibility)
 */
function removeUndefined<T extends Record<string, unknown>>(obj: T): Partial<T> {
  return Object.fromEntries(
    Object.entries(obj).filter(([, value]) => value !== undefined)
  ) as Partial<T>;
}

/**
 * Get Started Workflow Service
 *
 * Orchestrates the unified "Get Started" flow:
 * 1. Email verification via OTP
 * 2. Account status detection (Portal, WHMCS, SF)
 * 3. Guest eligibility check (creates SF Account + Case without OTP)
 * 4. Account completion for SF-only users
 * 5. Full signup with eligibility (SF + Case + WHMCS + Portal)
 */
@Injectable()
export class GetStartedWorkflowService {
  constructor(
    private readonly config: ConfigService,
    private readonly otpService: OtpService,
    private readonly sessionService: GetStartedSessionService,
    private readonly emailService: EmailService,
    private readonly usersService: UsersService,
    private readonly mappingsService: MappingsService,
    private readonly auditService: AuditService,
    private readonly salesforceAccountService: SalesforceAccountService,
    private readonly salesforceService: SalesforceFacade,
    private readonly opportunityResolution: OpportunityResolutionService,
    private readonly workflowCases: WorkflowCaseManager,
    private readonly whmcsDiscovery: WhmcsAccountDiscoveryService,
    private readonly whmcsSignup: SignupWhmcsService,
    private readonly userCreation: SignupUserCreationService,
    private readonly tokenService: AuthTokenService,
    private readonly lockService: DistributedLockService,
    @Inject(Logger) private readonly logger: Logger
  ) {}

  // ============================================================================
  // Email Verification
  // ============================================================================

  /**
   * Send OTP verification code to email
   *
   * @param request - The request containing the email
   * @param fingerprint - Optional request fingerprint for session binding
   */
  async sendVerificationCode(
    request: SendVerificationCodeRequest,
    fingerprint?: string
  ): Promise<SendVerificationCodeResponse> {
    const { email } = request;
    const normalizedEmail = email.toLowerCase().trim();

    try {
      // Generate OTP and store in Redis (with fingerprint for binding)
      const code = await this.otpService.generateAndStore(normalizedEmail, fingerprint);

      // Create session for this verification flow (token returned in verifyCode)
      await this.sessionService.create(normalizedEmail);

      // Send email with OTP code
      await this.sendOtpEmail(normalizedEmail, code);

      this.logger.log({ email: normalizedEmail }, "OTP verification code sent");

      return {
        sent: true,
        message: "Verification code sent to your email",
      };
    } catch (error) {
      this.logger.error(
        { error: extractErrorMessage(error), email: normalizedEmail },
        "Failed to send verification code"
      );

      return {
        sent: false,
        message: "Failed to send verification code. Please try again.",
      };
    }
  }

  /**
   * Verify OTP code and determine account status
   *
   * @param request - The request containing email and code
   * @param fingerprint - Optional request fingerprint for session binding check
   */
  async verifyCode(request: VerifyCodeRequest, fingerprint?: string): Promise<VerifyCodeResponse> {
    const { email, code } = request;
    const normalizedEmail = email.toLowerCase().trim();

    // Verify OTP (with fingerprint check - logs warning if different context)
    const otpResult = await this.otpService.verify(normalizedEmail, code, fingerprint);

    if (!otpResult.valid) {
      return {
        verified: false,
        error:
          otpResult.reason === "expired"
            ? "Code expired. Please request a new one."
            : otpResult.reason === "max_attempts"
              ? "Too many failed attempts. Please request a new code."
              : "Invalid code. Please try again.",
        attemptsRemaining: otpResult.attemptsRemaining,
      };
    }

    // Create verified session
    const sessionToken = await this.sessionService.create(normalizedEmail);

    // Check account status across all systems
    const accountStatus = await this.determineAccountStatus(normalizedEmail);

    // Get prefill data if account exists
    const prefill = this.getPrefillData(normalizedEmail, accountStatus);

    // Update session with verified status and account info
    // Build prefill data object without undefined values (exactOptionalPropertyTypes)
    const prefillData = {
      ...(prefill?.firstName && { firstName: prefill.firstName }),
      ...(prefill?.lastName && { lastName: prefill.lastName }),
      ...(prefill?.phone && { phone: prefill.phone }),
      ...(prefill?.address && { address: prefill.address }),
      ...(accountStatus.sfAccountId && { sfAccountId: accountStatus.sfAccountId }),
      ...(accountStatus.whmcsClientId !== undefined && {
        whmcsClientId: accountStatus.whmcsClientId,
      }),
      ...(prefill?.eligibilityStatus && { eligibilityStatus: prefill.eligibilityStatus }),
    };
    await this.sessionService.markEmailVerified(
      sessionToken,
      accountStatus.status,
      Object.keys(prefillData).length > 0 ? prefillData : undefined
    );

    this.logger.log(
      { email: normalizedEmail, accountStatus: accountStatus.status },
      "Email verified and account status determined"
    );

    return {
      verified: true,
      sessionToken,
      accountStatus: accountStatus.status,
      prefill,
    };
  }

  // ============================================================================
  // Guest Eligibility Check (No OTP Required)
  // ============================================================================

  /**
   * Guest eligibility check - NO email verification required
   *
   * Allows users to check availability without verifying email first.
   * Creates SF Account + eligibility case immediately.
   * Email verification happens later when user creates an account.
   *
   * Security:
   * - Email-level lock prevents concurrent requests creating duplicate SF accounts
   *
   * @param request - Guest eligibility request with name, email, address
   * @param fingerprint - Request fingerprint for logging/abuse detection
   */
  async guestEligibilityCheck(
    request: GuestEligibilityRequest,
    fingerprint?: string
  ): Promise<GuestEligibilityResponse> {
    const { email, firstName, lastName, address, phone, continueToAccount } = request;
    const normalizedEmail = email.toLowerCase().trim();

    this.logger.log(
      { email: normalizedEmail, continueToAccount, fingerprint },
      "Guest eligibility check initiated"
    );

    // Email-level lock to prevent concurrent requests for the same email
    const lockKey = `guest-eligibility:${normalizedEmail}`;

    try {
      return await this.lockService.withLock(
        lockKey,
        async () => {
          // Check if SF account already exists for this email
          let sfAccountId: string;

          const existingSf = await this.salesforceAccountService.findByEmail(normalizedEmail);

          if (existingSf) {
            sfAccountId = existingSf.id;
            this.logger.log(
              { email: normalizedEmail, sfAccountId },
              "Using existing SF account for guest eligibility check"
            );

            // Set portal source for existing accounts going through eligibility
            // This ensures we can track that they came through internet eligibility
            await this.salesforceService.updateAccountPortalFields(sfAccountId, {
              status: PORTAL_STATUS_NOT_YET,
              source: PORTAL_SOURCE_INTERNET_ELIGIBILITY,
            });
          } else {
            // Create new SF Account with portal fields set to "Not Yet" + "Internet Eligibility"
            const { accountId } = await this.salesforceAccountService.createAccount({
              firstName,
              lastName,
              email: normalizedEmail,
              phone: phone ?? "",
              portalSource: PORTAL_SOURCE_INTERNET_ELIGIBILITY,
            });
            sfAccountId = accountId;
            this.logger.log(
              { email: normalizedEmail, sfAccountId },
              "Created SF account for guest eligibility check"
            );
          }

          // Save Japanese address to SF Contact (if Japanese address fields provided)
          if (address.prefectureJa || address.cityJa || address.townJa) {
            await this.salesforceAccountService.updateContactAddress(sfAccountId, {
              mailingStreet: `${address.townJa || ""}${address.streetAddress || ""}`.trim(),
              mailingCity: address.cityJa || address.city,
              mailingState: address.prefectureJa || address.state,
              mailingPostalCode: address.postcode,
              mailingCountry: "Japan",
              buildingName: address.buildingName ?? null,
              roomNumber: address.roomNumber ?? null,
            });
            this.logger.debug({ sfAccountId }, "Updated SF Contact with Japanese address");
          }

          // Create eligibility case
          const { caseId } = await this.createEligibilityCase(sfAccountId, address);

          // Update Account eligibility status to Pending
          this.updateAccountEligibilityStatus(sfAccountId);

          // If user wants to continue to account creation, generate a handoff token
          let handoffToken: string | undefined;
          if (continueToAccount) {
            handoffToken = await this.sessionService.createGuestHandoffToken(normalizedEmail, {
              firstName,
              lastName,
              address: removeUndefined(address),
              ...(phone && { phone }),
              sfAccountId,
            });
            this.logger.debug(
              { email: normalizedEmail, handoffToken },
              "Created handoff token for account creation"
            );
          }

          return {
            submitted: true,
            requestId: caseId,
            sfAccountId,
            handoffToken,
            message: "Eligibility check submitted. We'll notify you of the results.",
          };
        },
        { ttlMs: 30_000 } // 30 second lock timeout
      );
    } catch (error) {
      this.logger.error(
        { error: extractErrorMessage(error), email: normalizedEmail },
        "Guest eligibility check failed"
      );

      return {
        submitted: false,
        message: "Failed to submit eligibility check. Please try again.",
      };
    }
  }

  // ============================================================================
  // Account Completion (SF-Only Users)
  // ============================================================================

  /**
   * Complete account for users with SF account but no WHMCS/Portal
   * Creates WHMCS client and Portal user, links to existing SF account
   *
   * Security:
   * - Session is locked to prevent double submissions
   * - Email-level lock prevents concurrent account creation
   */
  async completeAccount(request: CompleteAccountRequest): Promise<AuthResultInternal> {
    // Atomically acquire session lock and mark as used
    const sessionResult = await this.sessionService.acquireAndMarkAsUsed(
      request.sessionToken,
      "complete_account"
    );

    if (!sessionResult.success) {
      throw new BadRequestException(sessionResult.reason);
    }

    const session = sessionResult.session;

    if (!session.sfAccountId) {
      throw new BadRequestException("No Salesforce account found. Please check eligibility first.");
    }

    const { password, phone, dateOfBirth, gender } = request;
    const lockKey = `complete-account:${session.email}`;

    try {
      return await this.lockService.withLock(
        lockKey,
        async () => {
          // Verify SF account still exists
          const existingSf = await this.salesforceAccountService.findByEmail(session.email);
          if (!existingSf || existingSf.id !== session.sfAccountId) {
            throw new BadRequestException("Account verification failed. Please start over.");
          }

          // Check for existing WHMCS client (shouldn't exist for SF-only flow)
          const existingWhmcs = await this.whmcsDiscovery.findClientByEmail(session.email);
          if (existingWhmcs) {
            throw new ConflictException(
              "A billing account already exists. Please use the account migration flow."
            );
          }

          // Check for existing portal user
          const existingPortalUser = await this.usersService.findByEmailInternal(session.email);
          if (existingPortalUser) {
            throw new ConflictException("An account already exists. Please log in.");
          }

          const passwordHash = await argon2.hash(password);

          // Get address from session or SF
          const address = session.address;
          if (!address || !address.address1 || !address.city || !address.postcode) {
            throw new BadRequestException("Address information is incomplete.");
          }

          // Create WHMCS client
          const whmcsClient = await this.whmcsSignup.createClient({
            firstName: session.firstName!,
            lastName: session.lastName!,
            email: session.email,
            password,
            phone,
            address: {
              address1: address.address1,
              ...(address.address2 && { address2: address.address2 }),
              city: address.city,
              state: address.state ?? "",
              postcode: address.postcode,
              country: address.country ?? "Japan",
            },
            customerNumber: existingSf.accountNumber,
            dateOfBirth,
            gender,
          });

          // Create portal user and mapping
          const { userId } = await this.userCreation.createUserWithMapping({
            email: session.email,
            passwordHash,
            whmcsClientId: whmcsClient.clientId,
            sfAccountId: session.sfAccountId,
          });

          // Fetch fresh user and generate tokens
          const freshUser = await this.usersService.findByIdInternal(userId);
          if (!freshUser) {
            throw new Error("Failed to load created user");
          }

          await this.auditService.logAuthEvent(AuditAction.SIGNUP, userId, {
            email: session.email,
            whmcsClientId: whmcsClient.clientId,
            source: "get_started_complete_account",
          });

          const profile = mapPrismaUserToDomain(freshUser);
          const tokens = await this.tokenService.generateTokenPair({
            id: profile.id,
            email: profile.email,
          });

          // Update Salesforce portal flags
          await this.updateSalesforcePortalFlags(session.sfAccountId, whmcsClient.clientId);

          // Invalidate session (fully done)
          await this.sessionService.invalidate(request.sessionToken);

          this.logger.log(
            { email: session.email, userId },
            "Account completed successfully for SF-only user"
          );

          return {
            user: profile,
            tokens,
          };
        },
        { ttlMs: 60_000 }
      );
    } catch (error) {
      this.logger.error(
        { error: extractErrorMessage(error), email: session.email },
        "Account completion failed"
      );

      // Don't clear usedStatus on error - partial resources may have been created.
      // The user must verify their email again to start fresh.

      throw error;
    }
  }

  // ============================================================================
  // Full Signup with Eligibility (Inline Flow)
  // ============================================================================

  /**
   * Full signup with eligibility check - creates everything in one operation
   *
   * This is the primary signup path from the eligibility check page.
   * Creates SF Account + Case + WHMCS + Portal after email verification.
   *
   * Security:
   * - Session is locked to prevent double submissions (race condition protection)
   * - Email-level lock prevents concurrent signups for the same email
   * - Session is invalidated on success, cleared on partial failure for retry
   *
   * @param request - Signup request with all required data
   */
  async signupWithEligibility(request: SignupWithEligibilityRequest): Promise<{
    success: boolean;
    message?: string;
    eligibilityRequestId?: string;
    authResult?: AuthResultInternal;
  }> {
    // Atomically acquire session lock and mark as used
    const sessionResult = await this.sessionService.acquireAndMarkAsUsed(
      request.sessionToken,
      "signup_with_eligibility"
    );

    if (!sessionResult.success) {
      return {
        success: false,
        message: sessionResult.reason,
      };
    }

    const session = sessionResult.session;
    const { firstName, lastName, address, phone, password, dateOfBirth, gender } = request;
    const normalizedEmail = session.email;

    this.logger.log({ email: normalizedEmail }, "Starting signup with eligibility");

    // Email-level lock to prevent concurrent signups for the same email
    const lockKey = `signup-email:${normalizedEmail}`;

    try {
      return await this.lockService.withLock(
        lockKey,
        async () => {
          // Check for existing Portal user
          const existingPortalUser = await this.usersService.findByEmailInternal(normalizedEmail);
          if (existingPortalUser) {
            return {
              success: false,
              message: "An account already exists with this email. Please log in.",
            };
          }

          // Check for existing WHMCS client
          const existingWhmcs = await this.whmcsDiscovery.findClientByEmail(normalizedEmail);
          if (existingWhmcs) {
            return {
              success: false,
              message:
                "A billing account already exists with this email. Please use account linking instead.",
            };
          }

          // Check for existing SF Account or create new one
          let sfAccountId: string;
          let customerNumber: string | undefined;

          const existingSf = await this.salesforceAccountService.findByEmail(normalizedEmail);
          if (existingSf) {
            sfAccountId = existingSf.id;
            customerNumber = existingSf.accountNumber;
            this.logger.log(
              { email: normalizedEmail, sfAccountId },
              "Using existing SF account for signup"
            );

            // Set portal source for existing accounts going through eligibility signup
            // Source will be preserved when we activate the account later
            await this.salesforceService.updateAccountPortalFields(sfAccountId, {
              source: PORTAL_SOURCE_INTERNET_ELIGIBILITY,
            });
          } else {
            // Create new SF Account with portal fields set to "Not Yet" + "Internet Eligibility"
            const { accountId, accountNumber } = await this.salesforceAccountService.createAccount({
              firstName,
              lastName,
              email: normalizedEmail,
              phone: phone ?? "",
              portalSource: PORTAL_SOURCE_INTERNET_ELIGIBILITY,
            });
            sfAccountId = accountId;
            customerNumber = accountNumber;
            this.logger.log(
              { email: normalizedEmail, sfAccountId },
              "Created new SF account for signup"
            );
          }

          // Create eligibility case
          const { caseId: eligibilityRequestId } = await this.createEligibilityCase(
            sfAccountId,
            address
          );

          // Hash password
          const passwordHash = await argon2.hash(password);

          // Create WHMCS client
          const whmcsClient = await this.whmcsSignup.createClient({
            firstName,
            lastName,
            email: normalizedEmail,
            password,
            phone,
            address: {
              address1: address.address1,
              ...(address.address2 && { address2: address.address2 }),
              city: address.city,
              state: address.state ?? "",
              postcode: address.postcode,
              country: address.country ?? "Japan",
            },
            customerNumber,
            dateOfBirth,
            gender,
          });

          // Create Portal user and mapping
          const { userId } = await this.userCreation.createUserWithMapping({
            email: normalizedEmail,
            passwordHash,
            whmcsClientId: whmcsClient.clientId,
            sfAccountId,
          });

          // Fetch fresh user and generate tokens
          const freshUser = await this.usersService.findByIdInternal(userId);
          if (!freshUser) {
            throw new Error("Failed to load created user");
          }

          await this.auditService.logAuthEvent(AuditAction.SIGNUP, userId, {
            email: normalizedEmail,
            whmcsClientId: whmcsClient.clientId,
            source: "signup_with_eligibility",
          });

          const profile = mapPrismaUserToDomain(freshUser);
          const tokens = await this.tokenService.generateTokenPair({
            id: profile.id,
            email: profile.email,
          });

          // Update Salesforce portal flags
          await this.updateSalesforcePortalFlags(sfAccountId, whmcsClient.clientId);

          // Invalidate session (fully done, no retry needed)
          await this.sessionService.invalidate(request.sessionToken);

          // Send welcome email (includes eligibility info)
          await this.sendWelcomeWithEligibilityEmail(
            normalizedEmail,
            firstName,
            eligibilityRequestId
          );

          this.logger.log(
            { email: normalizedEmail, userId, eligibilityRequestId },
            "Signup with eligibility completed successfully"
          );

          return {
            success: true,
            eligibilityRequestId,
            authResult: {
              user: profile,
              tokens,
            },
          };
        },
        { ttlMs: 60_000 } // 60 second lock timeout for the full operation
      );
    } catch (error) {
      this.logger.error(
        { error: extractErrorMessage(error), email: normalizedEmail },
        "Signup with eligibility failed"
      );

      // Don't clear usedStatus on error - partial resources may have been created.
      // The user must verify their email again to start fresh.
      // This prevents potential duplicate resource creation on retry.

      return {
        success: false,
        message: "Account creation failed. Please verify your email again to retry.",
      };
    }
  }

  // ============================================================================
  // Private Helpers
  // ============================================================================

  private async sendOtpEmail(email: string, code: string): Promise<void> {
    const templateId = this.config.get<string>("EMAIL_TEMPLATE_OTP_VERIFICATION");

    if (templateId) {
      await this.emailService.sendEmail({
        to: email,
        subject: "Your verification code",
        templateId,
        dynamicTemplateData: {
          code,
          expiresMinutes: "10",
        },
      });
    } else {
      // Fallback to plain HTML
      await this.emailService.sendEmail({
        to: email,
        subject: "Your verification code",
        html: `
          <p>Your verification code is: <strong>${code}</strong></p>
          <p>This code expires in 10 minutes.</p>
          <p>If you didn't request this code, please ignore this email.</p>
        `,
      });
    }
  }

  private async sendWelcomeWithEligibilityEmail(
    email: string,
    firstName: string,
    eligibilityRequestId: string
  ): Promise<void> {
    const appBase = this.config.get<string>("APP_BASE_URL", "http://localhost:3000");
    const templateId = this.config.get<string>("EMAIL_TEMPLATE_WELCOME_WITH_ELIGIBILITY");

    if (templateId) {
      await this.emailService.sendEmail({
        to: email,
        subject: "Welcome! Your account is ready",
        templateId,
        dynamicTemplateData: {
          firstName,
          portalUrl: appBase,
          dashboardUrl: `${appBase}/account/dashboard`,
          eligibilityRequestId,
        },
      });
    } else {
      await this.emailService.sendEmail({
        to: email,
        subject: "Welcome! Your account is ready",
        html: `
          <p>Hi ${firstName},</p>
          <p>Welcome! Your account has been created successfully.</p>
          <p>We're also checking internet availability at your address. We'll notify you of the results within 1-2 business days.</p>
          <p>Reference ID: ${eligibilityRequestId}</p>
          <p>Log in to your dashboard: <a href="${appBase}/account/dashboard">${appBase}/account/dashboard</a></p>
        `,
      });
    }
  }

  private async determineAccountStatus(
    email: string
  ): Promise<{ status: AccountStatus; sfAccountId?: string; whmcsClientId?: number }> {
    // Check Portal user first
    const portalUser = await this.usersService.findByEmailInternal(email);
    if (portalUser) {
      const hasMapping = await this.mappingsService.hasMapping(portalUser.id);
      if (hasMapping) {
        return { status: ACCOUNT_STATUS.PORTAL_EXISTS };
      }
    }

    // Check WHMCS client
    const whmcsClient = await this.whmcsDiscovery.findClientByEmail(email);
    if (whmcsClient) {
      // Check if WHMCS is already mapped
      const mapping = await this.mappingsService.findByWhmcsClientId(whmcsClient.id);
      if (mapping) {
        return { status: ACCOUNT_STATUS.PORTAL_EXISTS };
      }
      return { status: ACCOUNT_STATUS.WHMCS_UNMAPPED, whmcsClientId: whmcsClient.id };
    }

    // Check Salesforce account
    const sfAccount = await this.salesforceAccountService.findByEmail(email);
    if (sfAccount) {
      // Check if SF is already mapped
      const mapping = await this.mappingsService.findBySfAccountId(sfAccount.id);
      if (mapping) {
        return { status: ACCOUNT_STATUS.PORTAL_EXISTS };
      }
      return { status: ACCOUNT_STATUS.SF_UNMAPPED, sfAccountId: sfAccount.id };
    }

    // No account exists
    return { status: ACCOUNT_STATUS.NEW_CUSTOMER };
  }

  private getPrefillData(
    email: string,
    accountStatus: { status: AccountStatus; sfAccountId?: string; whmcsClientId?: number }
  ): VerifyCodeResponse["prefill"] {
    // For SF-only accounts, we could query SF for the stored address/name
    // For now, return minimal data - frontend will handle input
    if (accountStatus.status === ACCOUNT_STATUS.SF_UNMAPPED && accountStatus.sfAccountId) {
      // TODO: Query SF for stored account details
      return {
        email,
      };
    }

    return undefined;
  }

  private async createEligibilityCase(
    sfAccountId: string,
    address: BilingualEligibilityAddress | SignupWithEligibilityRequest["address"]
  ): Promise<{ caseId: string; caseNumber: string }> {
    // Find or create Opportunity for Internet eligibility
    const { opportunityId, wasCreated: opportunityCreated } =
      await this.opportunityResolution.findOrCreateForInternetEligibility(sfAccountId);

    // Create eligibility case via workflow manager
    await this.workflowCases.notifyEligibilityCheck({
      accountId: sfAccountId,
      opportunityId,
      opportunityCreated,
      address: {
        address1: address.address1,
        ...(address.address2 ? { address2: address.address2 } : {}),
        city: address.city,
        state: address.state,
        postcode: address.postcode,
        ...(address.country ? { country: address.country } : {}),
      },
    });

    // Update Account eligibility status to Pending
    this.updateAccountEligibilityStatus(sfAccountId);

    // Generate a reference ID for the eligibility request
    // (WorkflowCaseManager.notifyEligibilityCheck doesn't return case ID as it's non-critical)
    const caseId = `eligibility:${sfAccountId}:${Date.now()}`;
    const caseNumber = `ELG-${Date.now().toString(36).toUpperCase()}`;

    return { caseId, caseNumber };
  }

  private updateAccountEligibilityStatus(sfAccountId: string): void {
    // TODO: Implement SF Account eligibility status update
    // This would update the SF Account eligibility fields using salesforceService
    this.logger.debug({ sfAccountId }, "Updating account eligibility status to Pending");
  }

  private async updateSalesforcePortalFlags(
    accountId: string,
    whmcsClientId: number,
    /** Optional source override - if not provided, source is not updated (preserves existing) */
    source?: typeof PORTAL_SOURCE_NEW_SIGNUP | typeof PORTAL_SOURCE_INTERNET_ELIGIBILITY
  ): Promise<void> {
    try {
      await this.salesforceService.updateAccountPortalFields(accountId, {
        status: PORTAL_STATUS_ACTIVE,
        // Only update source if explicitly provided - preserves existing source for eligibility flows
        ...(source && { source }),
        lastSignedInAt: new Date(),
        whmcsAccountId: whmcsClientId,
      });
    } catch (error) {
      this.logger.warn(
        { error: extractErrorMessage(error), accountId },
        "Failed to update Salesforce portal flags"
      );
    }
  }
}
