/**
 * User Enrichment Service
 * 
 * Handles automatic user lookup/creation and data enrichment for workflow creation
 */

import { User } from '@models/User';
import logger from '@utils/logger';
import { UserService } from './user.service';

const userService = new UserService();

interface SimplifiedApprovalLevel {
  email: string;
  tatHours: number;
  isFinalApprover?: boolean;
  levelNumber?: number;
  levelName?: string;
  approverId?: string;
  approverEmail?: string;
  approverName?: string;
}

interface EnrichedApprovalLevel {
  levelNumber: number;
  levelName: string;
  approverId: string;
  approverEmail: string;
  approverName: string;
  tatHours: number;
  isFinalApprover: boolean;
}

interface SimplifiedSpectator {
  email: string;
  userId?: string;
  userEmail?: string;
  userName?: string;
}

interface EnrichedSpectator {
  userId: string;
  userEmail: string;
  userName: string;
  participantType: 'SPECTATOR';
  canComment: boolean;
  canViewDocuments: boolean;
  canDownloadDocuments: boolean;
  notificationEnabled: boolean;
}

/**
 * Enrich approval levels with user data from database/AD
 * @param approvalLevels - Simplified approval levels (only email + tatHours required)
 * @returns Enriched approval levels with full user data
 */
export async function enrichApprovalLevels(
  approvalLevels: SimplifiedApprovalLevel[]
): Promise<EnrichedApprovalLevel[]> {
  const enriched: EnrichedApprovalLevel[] = [];
  const processedEmails = new Set<string>();

  for (let i = 0; i < approvalLevels.length; i++) {
    const level = approvalLevels[i];
    const email = level.email.toLowerCase();

    // Check for duplicate emails
    if (processedEmails.has(email)) {
      throw new Error(`Duplicate approver email found: ${email}. Each approver must have a unique email.`);
    }
    processedEmails.add(email);

    try {
      // Find or create user from AD
      let user = await User.findOne({ where: { email } });

      if (!user) {
        logger.info(`[UserEnrichment] User not found in DB, attempting to sync from AD: ${email}`);
        // Try to fetch and create user from AD
        try {
          user = await userService.ensureUserExists({ email }) as any;
        } catch (adError: any) {
          logger.error(`[UserEnrichment] Failed to sync user from AD: ${email}`, adError);
          throw new Error(`Approver email '${email}' not found in organization directory. Please verify the email address.`);
        }
      }

      const userId = (user as any).userId;
      const displayName = (user as any).displayName || (user as any).email;
      const designation = (user as any).designation || (user as any).jobTitle;
      const department = (user as any).department;

      // Auto-generate level name
      let levelName = level.levelName;
      if (!levelName) {
        if (designation) {
          levelName = `${designation} Approval`;
        } else if (department) {
          levelName = `${department} Approval`;
        } else {
          levelName = `Level ${i + 1} Approval`;
        }
      }

      // Auto-detect final approver (last level)
      const isFinalApprover = level.isFinalApprover !== undefined
        ? level.isFinalApprover
        : (i === approvalLevels.length - 1);

      enriched.push({
        levelNumber: level.levelNumber || (i + 1),
        levelName,
        approverId: userId,
        approverEmail: email,
        approverName: displayName,
        tatHours: level.tatHours,
        isFinalApprover,
      });

      logger.info(`[UserEnrichment] Enriched approval level ${i + 1}: ${email} -> ${displayName} (${levelName})`);
    } catch (error: any) {
      logger.error(`[UserEnrichment] Failed to enrich approval level for ${email}:`, error);
      throw error;
    }
  }

  return enriched;
}

/**
 * Enrich spectators with user data from database/AD
 * @param spectators - Simplified spectators (only email required)
 * @returns Enriched spectators with full user data
 */
export async function enrichSpectators(
  spectators: SimplifiedSpectator[]
): Promise<EnrichedSpectator[]> {
  if (!spectators || spectators.length === 0) {
    return [];
  }

  const enriched: EnrichedSpectator[] = [];
  const processedEmails = new Set<string>();

  for (const spectator of spectators) {
    const email = spectator.email.toLowerCase();

    // Check for duplicate emails
    if (processedEmails.has(email)) {
      throw new Error(`Duplicate spectator email found: ${email}. Each spectator must have a unique email.`);
    }
    processedEmails.add(email);

    try {
      // Find or create user from AD
      let user = await User.findOne({ where: { email } });

      if (!user) {
        logger.info(`[UserEnrichment] User not found in DB, attempting to sync from AD: ${email}`);
        try {
          user = await userService.ensureUserExists({ email }) as any;
        } catch (adError: any) {
          logger.error(`[UserEnrichment] Failed to sync user from AD: ${email}`, adError);
          throw new Error(`Spectator email '${email}' not found in organization directory. Please verify the email address.`);
        }
      }

      const userId = (user as any).userId;
      const displayName = (user as any).displayName || (user as any).email;

      enriched.push({
        userId,
        userEmail: email,
        userName: displayName,
        participantType: 'SPECTATOR',
        canComment: true,
        canViewDocuments: true,
        canDownloadDocuments: false,
        notificationEnabled: true,
      });

      logger.info(`[UserEnrichment] Enriched spectator: ${email} -> ${displayName}`);
    } catch (error: any) {
      logger.error(`[UserEnrichment] Failed to enrich spectator ${email}:`, error);
      throw error;
    }
  }

  return enriched;
}

/**
 * Validate and ensure initiator exists in database
 * @param initiatorId - User ID of the initiator
 * @returns User object if valid
 * @throws Error if initiator not found or invalid
 */
export async function validateInitiator(initiatorId: string): Promise<any> {
  const user = await User.findByPk(initiatorId);

  if (!user) {
    throw new Error(`Invalid initiator: User with ID '${initiatorId}' not found. Please ensure you are logged in with a valid account.`);
  }

  return user;
}

/**
 * Validate dealer user exists with jobTitle 'Dealer' and employeeId matching dealerCode
 * @param dealerCode - The dealer code to validate
 * @returns User object if valid
 * @throws Error if dealer validation fails
 */
export async function validateDealerUser(dealerCode: string): Promise<User> {
  logger.info(`[UserEnrichment] Validating dealer user for code: ${dealerCode}`);

  const user = await User.findOne({
    where: {
      employeeNumber: dealerCode,
      jobTitle: 'Dealer',
      isActive: true
    }
  });

  if (!user) {
    logger.warn(`[UserEnrichment] Dealer validation failed: No active user found with 'Dealer' job title and employee ID '${dealerCode}'`);
    throw new Error(`Dealer validation failed: No active user found with 'Dealer' job title and employee ID '${dealerCode}'. If this user exists, please ensure their job title is set to 'Dealer' and their employee ID matches the dealer code.`);
  }

  logger.info(`[UserEnrichment] Dealer validation successful for ${dealerCode}: ${user.displayName || user.email}`);
  return user;
}
