
import { Program, ProgramType } from '../entities';
import { Logger } from '@nestjs/common';
import { RegistrationStatusEnum } from '../enum/registration-status.enum';
import { PaymentStatusEnum } from '../enum/payment-status.enum';
import { TravelStatusEnum } from '../enum/travel-status.enum';
// Create a logger instance for this module
const logger = new Logger('RegistrationFlowConfig');

/**
 * Registration Flow Configuration
 * 
 * This configuration determines the registration flow based on program settings.
 * Priority: Program config > ProgramType config
 */

export interface RegistrationFlowConfig {
  requiresPayment: boolean;
  involvesTravel: boolean;
  requiresApproval: boolean;
  shouldSendTerms: boolean;
  parentalConsentEnabled: boolean;
  parentalConsentFormAsAttachment: boolean;
  parentalConsentUploadDeadline: Date | null;
  parentalConsentFormContent: string | null;
  programId?: number;
  programTypeKey?: string;
}

export interface FlowDecision {
  shouldAutoApprove: boolean;
  shouldCheckSeatsNow: boolean;
  shouldCheckSeatsAfterApproval: boolean;
  initialStatus: string;
  autoApprovalReason?: string;
}

/**
 * Extract registration flow configuration from Program or ProgramType
 * Priority: Program config first, fallback to ProgramType
 */
export function getRegistrationFlowConfig(
  program: Program,
  programType?: ProgramType,
  session?: {
    shouldSendTerms?: boolean;
    parentalConsentEnabled?: boolean;
    parentalConsentFormAsAttachment?: boolean;
    parentalConsentUploadDeadline?: Date;
    parentalConsentFormContent?: string;
  },
): RegistrationFlowConfig {
  // Priority 1: Check Program entity configuration
  const requiresPayment = program.requiresPayment ?? programType?.requiresPayment ?? false;
  const involvesTravel = program.involvesTravel ?? programType?.involvesTravel ?? false;
  const requiresApproval = program.requiresApproval ?? programType?.requiresApproval ?? false;
  // Session → Program → false
  const shouldSendTerms = session?.shouldSendTerms ?? program.shouldSendTerms ?? false;
  // Session → Program → ProgramType → false
  const parentalConsentEnabled = session?.parentalConsentEnabled ?? program.parentalConsentEnabled ?? programType?.parentalConsentEnabled ?? false;
  const parentalConsentFormAsAttachment = session?.parentalConsentFormAsAttachment ?? program.parentalConsentFormAsAttachment ?? programType?.parentalConsentFormAsAttachment ?? true;
  const parentalConsentUploadDeadline = session?.parentalConsentUploadDeadline ?? program.parentalConsentUploadDeadline ?? programType?.parentalConsentUploadDeadline ?? null;
  const parentalConsentFormContent = session?.parentalConsentFormContent ?? program.parentalConsentFormContent ?? programType?.parentalConsentFormContent ?? null;


  logger.log(`[FLOW CONFIG] getRegistrationFlowConfig:`, {
    programId: program.id,
    programTypeKey: programType?.key,
    requiresPayment,
    involvesTravel,
    requiresApproval,
    shouldSendTerms,
    parentalConsentEnabled,
  });

  return {
    requiresPayment,
    involvesTravel,
    requiresApproval,
    shouldSendTerms,
    parentalConsentEnabled,
    parentalConsentFormAsAttachment,
    parentalConsentUploadDeadline,
    parentalConsentFormContent,
    programId: program.id,
    programTypeKey: programType?.key,
  };
}

/**
 * Determine the flow decisions based on configuration
 */
export function determineFlowDecisions(
  config: RegistrationFlowConfig
): FlowDecision {
  const { requiresApproval, requiresPayment, involvesTravel } = config;

  // Decision 1: Should auto-approve?
  const shouldAutoApprove = !requiresApproval;

  // Decision 2: When to check seats?
  // If approval required, check seats AFTER approval
  // If no approval required, check seats NOW
  const shouldCheckSeatsNow = !requiresApproval;
  const shouldCheckSeatsAfterApproval = requiresApproval;

  // Decision 3: Initial registration status
  let initialStatus: string;
  if (requiresApproval) {
    initialStatus = 'PENDING'; // Will need approval
  } else if (requiresPayment || involvesTravel) {
    initialStatus = 'PENDING'; // Will need payment/travel
  } else {
    initialStatus = 'COMPLETED'; // No requirements
  }

  // Decision 4: Auto-approval reason
  let autoApprovalReason: string | undefined;
  if (shouldAutoApprove) {
    autoApprovalReason = `Auto-approved: Program ${config.programTypeKey || config.programId} does not require manual approval`;
  }


  logger.log(`[FLOW CONFIG] determineFlowDecisions:`, {
    requiresApproval,
    requiresPayment,
    involvesTravel,
    shouldAutoApprove,
    shouldCheckSeatsNow,
    shouldCheckSeatsAfterApproval,
    initialStatus,
    autoApprovalReason,
  });

  return {
    shouldAutoApprove,
    shouldCheckSeatsNow,
    shouldCheckSeatsAfterApproval,
    initialStatus,
    autoApprovalReason,
  };
}

/**
 * Determine next status after payment completion
 * Now checks actual registration details instead of just config
 */
export function determineStatusAfterPayment(
  config: RegistrationFlowConfig,
  registration: any
): string {

  logger.log(`[FLOW CONFIG] determineStatusAfterPayment: Checking registration details`, {
    registrationId: registration.id,
    requiresTravel: config.involvesTravel,
    requiresApproval: config.requiresApproval,
  });

  // Check actual payment completion
  const paymentCompleted = 
    registration.isFreeSeat || 
    registration.paymentDetails?.some((p: any) => 
      p.paymentStatus === 'online_completed' || p.paymentStatus === 'offline_completed'
    );


  if (!paymentCompleted) {
    logger.log(`[FLOW CONFIG] determineStatusAfterPayment: Payment not completed, stay PENDING`);
    return 'PENDING';
  }

  // Check if travel is required and completed

  if (config.involvesTravel) {
    const travelInfoCompleted = registration.travelInfo?.some((t: any) => t.travelInfoStatus === 'completed');
    const travelPlanCompleted = registration.travelPlans?.some((tp: any) => tp.travelPlanStatus === 'completed');
    if (!travelInfoCompleted || !travelPlanCompleted) {
      logger.log(`[FLOW CONFIG] determineStatusAfterPayment: Travel required but not completed, stay PENDING`);
      return 'PENDING';
    }
  }

  // Check if approval is required and completed

  if (config.requiresApproval) {
    const approvalCompleted = registration.approvals?.some((a: any) => a.approvalStatus === 'approved');
    if (!approvalCompleted) {
      logger.log(`[FLOW CONFIG] determineStatusAfterPayment: Approval required but not completed, stay PENDING`);
      return 'PENDING';
    }
  }

  logger.log(`[FLOW CONFIG] determineStatusAfterPayment: All requirements met, mark as COMPLETED`);
  return 'COMPLETED';
}

/**
 * Determine the registration status when an admin RELEASES a waitlisted seat.
 *
 * Driven by program config (payment / travel applicability) plus the registration's current
 * payment + travel completion. Unlike the post-payment/approval helpers (which only ever return
 * PENDING|COMPLETED), this can also keep the registration WAITLISTED when payment has not
 * meaningfully progressed. Matrix:
 *
 *   - No payment & no travel required                  -> COMPLETED
 *   - Payment required, no travel:
 *         online/offline completed (or free seat)      -> COMPLETED
 *         offline pending                              -> PENDING
 *         null / online pending / failed               -> WAITLISTED
 *   - Payment & travel required:
 *         payment completed + travel completed         -> COMPLETED
 *         payment completed + travel pending           -> PENDING
 *         offline pending (any travel state)           -> PENDING
 *         null / online pending / failed (any travel)  -> WAITLISTED
 *   - Travel required, no payment (not in the spec; sensible default):
 *         travel completed -> COMPLETED, else PENDING
 */
export function determineStatusAfterWaitlistRelease(
  config: RegistrationFlowConfig,
  registration: any,
): RegistrationStatusEnum {
  const paymentStatuses: PaymentStatusEnum[] = (registration.paymentDetails ?? []).map(
    (payment: any) => payment.paymentStatus,
  );
  const paymentCompleted =
    !!registration.isFreeSeat ||
    paymentStatuses.some(
      (paymentStatus) =>
        paymentStatus === PaymentStatusEnum.ONLINE_COMPLETED ||
        paymentStatus === PaymentStatusEnum.OFFLINE_COMPLETED,
    );
  const offlinePending = paymentStatuses.some(
    (paymentStatus) => paymentStatus === PaymentStatusEnum.OFFLINE_PENDING,
  );

  const travelCompleted =
    !!registration.travelInfo?.some(
      (travelInfo: any) => travelInfo.travelInfoStatus === TravelStatusEnum.COMPLETED,
    ) &&
    !!registration.travelPlans?.some(
      (travelPlan: any) => travelPlan.travelPlanStatus === TravelStatusEnum.COMPLETED,
    );

  logger.log(`[FLOW CONFIG] determineStatusAfterWaitlistRelease`, {
    registrationId: registration.id,
    isFreeSeat: !!registration.isFreeSeat,
    requiresPayment: config.requiresPayment,
    involvesTravel: config.involvesTravel,
    paymentCompleted,
    offlinePending,
    travelCompleted,
  });

  // Free seat → COMPLETED outright, regardless of payment or travel state.
  if (registration.isFreeSeat) {
    return RegistrationStatusEnum.COMPLETED;
  }

  // Rule 3: neither payment nor travel applicable.
  if (!config.requiresPayment && !config.involvesTravel) {
    return RegistrationStatusEnum.COMPLETED;
  }

  // Travel applicable, payment not (not in the spec — mirror the payment-less travel gate).
  if (!config.requiresPayment && config.involvesTravel) {
    return travelCompleted ? RegistrationStatusEnum.COMPLETED : RegistrationStatusEnum.PENDING;
  }

  // Rule 1: payment applicable, travel not.
  if (config.requiresPayment && !config.involvesTravel) {
    if (paymentCompleted) return RegistrationStatusEnum.COMPLETED;
    if (offlinePending) return RegistrationStatusEnum.PENDING;
    return RegistrationStatusEnum.WAITLISTED;
  }

  // Rule 2: payment AND travel applicable.
  if (paymentCompleted) {
    return travelCompleted ? RegistrationStatusEnum.COMPLETED : RegistrationStatusEnum.PENDING;
  }
  if (offlinePending) {
    return RegistrationStatusEnum.PENDING;
  }
  return RegistrationStatusEnum.WAITLISTED;
}

/**
 * Determine next status after travel completion
 * Now checks actual registration details instead of just config
 */
export function determineStatusAfterTravel(
  config: RegistrationFlowConfig,
  registration: any
): string {

  logger.log(`[FLOW CONFIG] determineStatusAfterTravel: Checking registration details`, {
    registrationId: registration.id,
    requiresPayment: config.requiresPayment,
    requiresApproval: config.requiresApproval,
  });

  // Check actual travel completion
  const travelInfoCompleted = registration.travelInfo?.some((t: any) => t.travelInfoStatus === 'completed');
  const travelPlanCompleted = registration.travelPlans?.some((tp: any) => tp.travelPlanStatus === 'completed');
  

  if (!travelInfoCompleted || !travelPlanCompleted) {
    logger.log(`[FLOW CONFIG] determineStatusAfterTravel: Travel not completed, stay PENDING`);
    return 'PENDING';
  }

  // Check if payment is required and completed

  if (config.requiresPayment) {
    const paymentCompleted = 
      registration.isFreeSeat || 
      registration.paymentDetails?.some((p: any) => 
        p.paymentStatus === 'online_completed' || p.paymentStatus === 'offline_completed'
      );
    if (!paymentCompleted) {
      logger.log(`[FLOW CONFIG] determineStatusAfterTravel: Payment required but not completed, stay PENDING`);
      return 'PENDING';
    }
  }

  // Check if approval is required and completed

  if (config.requiresApproval) {
    const approvalCompleted = registration.approvals?.some((a: any) => a.approvalStatus === 'approved');
    if (!approvalCompleted) {
      logger.log(`[FLOW CONFIG] determineStatusAfterTravel: Approval required but not completed, stay PENDING`);
      return 'PENDING';
    }
  }

  logger.log(`[FLOW CONFIG] determineStatusAfterTravel: All requirements met, mark as COMPLETED`);
  return 'COMPLETED';
}

/**
 * Determine next status after approval
 * Now checks actual registration details instead of just approval status
 */
export function determineStatusAfterApproval(
  config: RegistrationFlowConfig,
  registration: any
): string {

  logger.log(`[FLOW CONFIG] determineStatusAfterApproval: Checking registration details`, {
    registrationId: registration.id,
    requiresPayment: config.requiresPayment,
    requiresTravel: config.involvesTravel,
  });

  // Check actual approval status
  const approvalStatus = registration.approvals?.find((a: any) => a.deletedAt === null)?.approvalStatus;
  

  if (approvalStatus === 'rejected') {
    logger.log(`[FLOW CONFIG] determineStatusAfterApproval: Approval REJECTED`);
    return 'REJECTED';
  }

  if (approvalStatus !== 'approved') {
    logger.log(`[FLOW CONFIG] determineStatusAfterApproval: Approval not completed, stay PENDING`);
    return 'PENDING';
  }

  // Check if payment is required and completed

  if (config.requiresPayment) {
    const paymentCompleted = 
      registration.isFreeSeat || 
      registration.paymentDetails?.some((p: any) => 
        p.paymentStatus === 'online_completed' || p.paymentStatus === 'offline_completed'
      );
    if (!paymentCompleted) {
      logger.log(`[FLOW CONFIG] determineStatusAfterApproval: Payment required but not completed, stay PENDING`);
      return 'PENDING';
    }
  }

  // Check if travel is required and completed

  if (config.involvesTravel) {
    const travelInfoCompleted = registration.travelInfo?.some((t: any) => t.travelInfoStatus === 'completed');
    const travelPlanCompleted = registration.travelPlans?.some((tp: any) => tp.travelPlanStatus === 'completed');
    if (!travelInfoCompleted || !travelPlanCompleted) {
      logger.log(`[FLOW CONFIG] determineStatusAfterApproval: Travel required but not completed, stay PENDING`);
      return 'PENDING';
    }
  }

  logger.log(`[FLOW CONFIG] determineStatusAfterApproval: All requirements met, mark as COMPLETED`);
  return 'COMPLETED';
}

/**
 * Check if registration can move to COMPLETED status
 * Legacy function - kept for backward compatibility
 */
export function canCompleteRegistration(
  config: RegistrationFlowConfig,
  paymentCompleted: boolean,
  travelCompleted: boolean,
  approvalCompleted: boolean
): boolean {
  // All required items must be completed
  if (config.requiresPayment && !paymentCompleted) {
    logger.log(`[FLOW CONFIG] canCompleteRegistration: Payment not completed`);
    return false;
  }
  if (config.involvesTravel && !travelCompleted) {
    logger.log(`[FLOW CONFIG] canCompleteRegistration: Travel not completed`);
    return false;
  }
  if (config.requiresApproval && !approvalCompleted) {
    logger.log(`[FLOW CONFIG] canCompleteRegistration: Approval not completed`);
    return false;
  }

  logger.log(`[FLOW CONFIG] canCompleteRegistration: All requirements met, can complete`);
  return true;
}

/**
 * Check if registration can move to COMPLETED status based on actual registration details
 * This is the preferred method that checks actual registration state
 */
export function canCompleteRegistrationFromDetails(
  config: RegistrationFlowConfig,
  registration: any
): boolean {

  logger.log(`[FLOW CONFIG] canCompleteRegistrationFromDetails: Checking registration`, {
    registrationId: registration.id,
    requiresPayment: config.requiresPayment,
    requiresTravel: config.involvesTravel,
    requiresApproval: config.requiresApproval,
  });
    // Check if registration is in a blocked status (cannot auto-complete)
  if (registration.registrationStatus === RegistrationStatusEnum.CANCELLED || 
      registration.registrationStatus === RegistrationStatusEnum.WAITLISTED || 
      registration.registrationStatus === RegistrationStatusEnum.DRAFT || 
      registration.registrationStatus === RegistrationStatusEnum.SAVE_AS_DRAFT || 
      registration.registrationStatus === RegistrationStatusEnum.REJECTED) {
    logger.log(`[FLOW CONFIG] canCompleteRegistrationFromDetails: Status ${registration.registrationStatus} cannot auto-complete`);
    return false;
  }

  // Check payment completion

  if (config.requiresPayment) {
    const paymentCompleted = 
      registration.isFreeSeat || 
      registration.paymentDetails?.some((p: any) => 
        p.paymentStatus === 'online_completed' || p.paymentStatus === 'offline_completed'
      );
    if (!paymentCompleted) {
      logger.log(`[FLOW CONFIG] canCompleteRegistrationFromDetails: Payment not completed`, {
        isFreeSeat: registration.isFreeSeat,
        paymentDetails: registration.paymentDetails?.map((p: any) => ({ 
          paymentStatus: p.paymentStatus,
          allocateSeatIfOfflinePending: registration.program?.allocateSeatIfOfflinePending 
        })),
      });
      return false;
    }
  }

  // Check travel completion

  if (config.involvesTravel) {
    const travelInfoCompleted = registration.travelInfo?.some((t: any) => t.travelInfoStatus === 'completed');
    const travelPlanCompleted = registration.travelPlans?.some((tp: any) => tp.travelPlanStatus === 'completed');
    if (!travelInfoCompleted || !travelPlanCompleted) {
      logger.log(`[FLOW CONFIG] canCompleteRegistrationFromDetails: Travel not completed`);
      return false;
    }
  }

  // Check approval completion
  if (config.requiresApproval) {
    const approvalCompleted = registration.approvals?.some((a: any) => a.approvalStatus === 'approved' && a.deletedAt === null);
    if (!approvalCompleted) {
      logger.log(`[FLOW CONFIG] canCompleteRegistrationFromDetails: Approval not completed`);
      return false;
    }
  }

  logger.log(`[FLOW CONFIG] canCompleteRegistrationFromDetails: All requirements met, can complete`);
  return true;
}

/**
 * Determine the appropriate status based on registration details and config
 * This is a comprehensive helper that checks all requirements
 */
export function determineRegistrationStatus(
  config: RegistrationFlowConfig,
  registration: any
): string {

  logger.log(`[FLOW CONFIG] determineRegistrationStatus: Checking registration`, {
    registrationId: registration.id,
    currentStatus: registration.registrationStatus,
  });

  // Check approval first if required

  if (config.requiresApproval) {
    const approvalStatus = registration.approvals?.find((a: any) => a.deletedAt === null)?.approvalStatus;
    if (!approvalStatus || approvalStatus === 'pending') {
      logger.log(`[FLOW CONFIG] determineRegistrationStatus: Approval pending`);
      return 'PENDING';
    }
    if (approvalStatus === 'rejected') {
      logger.log(`[FLOW CONFIG] determineRegistrationStatus: Approval rejected`);
      return 'REJECTED';
    }
    if (approvalStatus === 'on_hold') {
      logger.log(`[FLOW CONFIG] determineRegistrationStatus: Approval on hold`);
      return 'ON_HOLD';
    }
  }

  // Check if all requirements are met

  if (canCompleteRegistrationFromDetails(config, registration)) {
    logger.log(`[FLOW CONFIG] determineRegistrationStatus: All requirements met, COMPLETED`);
    return 'COMPLETED';
  }

  // Still pending some requirements
  logger.log(`[FLOW CONFIG] determineRegistrationStatus: Some requirements pending, PENDING`);
  return 'PENDING';
}

/**
 * Validate if a status transition is allowed
 * NOTE: All transitions are allowed to support flexible status management.
 * Status can move from COMPLETED to PENDING, ON_HOLD, etc.
 */
export function isStatusTransitionAllowed(
  fromStatus: string,
  toStatus: string
): { isValid: boolean; reason?: string } {
  // Allow all status transitions - no restrictions
  // This enables flexible status management where registrations can be
  // moved back to PENDING from COMPLETED, put ON_HOLD, etc.
  return { isValid: true };
}

/**
 * Get allowed target statuses from any given status
 * Returns all possible statuses since all transitions are allowed
 */
export function getAllowedTargetStatuses(currentStatus: string): string[] {
  return [
    'DRAFT',
    'SAVE_AS_DRAFT',
    'PENDING',
    'PENDING_APPROVAL',
    'WAITLISTED',
    'COMPLETED',
    'CANCELLED',
    'REJECTED',
    'ON_HOLD',
  ];
}
