import { RegisterClass } from '@memberjunction/global';
import { LearnWorldsBaseAction } from '../learnworlds-base.action';
import { ActionParam, ActionResultSimple, RunActionParams } from '@memberjunction/actions-base';
import { BaseAction } from '@memberjunction/actions';
import { UserInfo } from '@memberjunction/core';
import {
  GetUserDetailsParams,
  GetUserDetailsResult,
  LearnWorldsUserDetailsFull,
  UserDetailEnrollment,
  LWApiUser,
  LWApiEnrollmentStatus,
  LWApiProgressData,
} from '../interfaces';

/**
 * Extended raw user shape returned by the LearnWorlds GET /users/{id} endpoint.
 * Includes fields beyond the basic LWApiUser.
 */
interface LWUserDetailsResponse extends LWApiUser {
  profile_image?: string;
  description?: string;
  country?: string;
  language?: string;
  phone?: string;
  last_activity?: string | number;
  certificates_count?: number;
  badges_count?: number;
  points?: number;
  level?: string;
  email_notifications?: boolean;
  two_factor_enabled?: boolean;
  agreed_to_terms?: boolean;
  marketing_consent?: boolean;
}

/**
 * Raw enrollment shape from the LearnWorlds GET /users/{id}/enrollments endpoint
 */
interface LWEnrollmentData extends LWApiEnrollmentStatus {
  course_id?: string;
  course?: { id?: string; title?: string };
  course_title?: string;
  enrolled_at?: string;
  created?: string;
  progress?: LWApiProgressData;
  completed_at?: string;
  expires_at?: string;
  last_accessed_at?: string;
  time_spent?: number;
  certificate_url?: string;
  grade?: number;
  final_grade?: number;
}

/**
 * Raw enrollments list response
 */
interface LWEnrollmentsListResponse {
  data?: LWEnrollmentData[];
}

/**
 * Raw stats response from the LearnWorlds stats endpoint
 */
interface LWStatsResponse {
  total_time_spent?: number;
  certificates_earned?: number;
  badges_earned?: number;
  points?: number;
}

/**
 * Action to retrieve detailed information about a specific LearnWorlds user
 */
@RegisterClass(BaseAction, 'GetLearnWorldsUserDetailsAction')
export class GetLearnWorldsUserDetailsAction extends LearnWorldsBaseAction {
  /**
   * Description of the action
   */
  public get Description(): string {
    return 'Retrieves comprehensive details about a specific user in LearnWorlds including profile, enrollments, progress, and achievements';
  }

  /**
   * Typed public method for direct (non-framework) callers.
   * Throws on failure.
   */
  public async GetUserDetails(params: GetUserDetailsParams, contextUser: UserInfo): Promise<GetUserDetailsResult> {
    this.SetCompanyContext(params.CompanyID);

    if (!params.UserID) {
      throw new Error('UserID parameter is required');
    }

    const includeEnrollments = params.IncludeEnrollments ?? true;
    const includeStats = params.IncludeStats ?? true;

    // Fetch the user from the API
    const userResponse = await this.makeLearnWorldsRequest<LWUserDetailsResponse>(`users/${params.UserID}`, 'GET', undefined, contextUser);

    // Map basic user details
    const userDetails = this.mapUserDetails(userResponse);

    // Get enrollments if requested
    if (includeEnrollments) {
      await this.loadEnrollments(userDetails, params.UserID, contextUser);
    }

    // Get additional stats if requested
    if (includeStats) {
      await this.loadStats(userDetails, params.UserID, contextUser);
    }

    // Build summary
    const summary = this.createUserSummary(userDetails);

    return {
      UserDetails: userDetails,
      Summary: summary,
    };
  }

  /**
   * Framework entry point -- delegates to the typed public method.
   */
  protected async InternalRunAction(params: RunActionParams): Promise<ActionResultSimple> {
    const { Params, ContextUser } = params;
    this.params = Params;

    try {
      if (!ContextUser) {
        return this.buildErrorResult('ERROR', 'Context user is required for LearnWorlds API calls', Params);
      }

      const typedParams = this.extractGetUserDetailsParams(Params);
      const result = await this.GetUserDetails(typedParams, ContextUser);

      this.setOutputParam(Params, 'UserDetails', result.UserDetails);
      this.setOutputParam(Params, 'Summary', result.Summary);

      return this.buildSuccessResult(`Successfully retrieved details for user ${result.UserDetails.email}`, Params);
    } catch (error) {
      const msg = error instanceof Error ? error.message : 'Unknown error occurred';
      return this.buildErrorResult('ERROR', msg, Params);
    }
  }

  /**
   * Extract typed params from the generic ActionParam array
   */
  private extractGetUserDetailsParams(params: ActionParam[]): GetUserDetailsParams {
    return {
      CompanyID: this.getRequiredStringParam(params, 'CompanyID'),
      UserID: this.getRequiredStringParam(params, 'UserID'),
      IncludeEnrollments: this.getOptionalBooleanParam(params, 'IncludeEnrollments', true),
      IncludeStats: this.getOptionalBooleanParam(params, 'IncludeStats', true),
    };
  }

  /**
   * Map LearnWorlds user data to detailed interface
   */
  private mapUserDetails(lwUser: LWUserDetailsResponse): LearnWorldsUserDetailsFull {
    return {
      id: lwUser.id || lwUser._id || '',
      email: lwUser.email,
      username: lwUser.username || lwUser.email,
      firstName: lwUser.first_name,
      lastName: lwUser.last_name,
      fullName: lwUser.full_name || `${lwUser.first_name || ''} ${lwUser.last_name || ''}`.trim(),
      status: this.mapUserStatus(lwUser.status || 'active'),
      role: lwUser.role || 'student',
      createdAt: this.parseLearnWorldsDate(lwUser.created || lwUser.created_at || ''),
      lastLoginAt: lwUser.last_login ? this.parseLearnWorldsDate(lwUser.last_login) : undefined,
      avatarUrl: lwUser.avatar_url || lwUser.profile_image,
      bio: lwUser.bio || lwUser.description,
      location: lwUser.location || lwUser.country,
      timezone: lwUser.timezone,
      language: lwUser.language || 'en',
      phone: lwUser.phone,
      tags: lwUser.tags || [],
      customFields: lwUser.custom_fields || {},

      // Initialize statistics (overwritten by enrollment / stats loading)
      totalCourses: 0,
      completedCourses: 0,
      inProgressCourses: 0,
      notStartedCourses: 0,
      totalTimeSpent: 0,
      averageCompletionRate: 0,
      lastActivityDate: lwUser.last_activity ? this.parseLearnWorldsDate(lwUser.last_activity) : undefined,

      // Achievement data
      totalCertificates: lwUser.certificates_count || 0,
      totalBadges: lwUser.badges_count || 0,
      points: lwUser.points || 0,
      level: lwUser.level,

      // Account settings
      emailNotifications: lwUser.email_notifications,
      twoFactorEnabled: lwUser.two_factor_enabled,
      agreedToTerms: lwUser.agreed_to_terms,
      marketingConsent: lwUser.marketing_consent,
    };
  }

  /**
   * Fetch and attach enrollment data to userDetails.
   */
  private async loadEnrollments(userDetails: LearnWorldsUserDetailsFull, userId: string, contextUser: UserInfo): Promise<void> {
    const enrollmentsResponse = await this.makeLearnWorldsRequest<LWEnrollmentsListResponse>(`users/${userId}/courses`, 'GET', undefined, contextUser);

    if (enrollmentsResponse.data) {
      userDetails.enrollments = enrollmentsResponse.data.map((e) => this.mapEnrollment(e));
      Object.assign(userDetails, this.calculateEnrollmentStats(userDetails.enrollments));
    }
  }

  /**
   * Fetch and merge additional stats into userDetails.
   */
  private async loadStats(userDetails: LearnWorldsUserDetailsFull, userId: string, contextUser: UserInfo): Promise<void> {
    try {
      const statsResponse = await this.makeLearnWorldsRequest<LWStatsResponse>(`users/${userId}/stats`, 'GET', undefined, contextUser);

      if (statsResponse) {
        Object.assign(userDetails, this.extractStatistics(statsResponse));
      }
    } catch (error) {
      console.warn(`Stats endpoint unavailable for user ${userId}:`, error instanceof Error ? error.message : error);
    }
  }

  /**
   * Map raw enrollment data to our typed UserDetailEnrollment
   */
  private mapEnrollment(enrollment: LWEnrollmentData): UserDetailEnrollment {
    const progress = this.calculateProgress(enrollment.progress || {});

    return {
      courseId: enrollment.course_id || enrollment.course?.id || '',
      courseTitle: enrollment.course_title || enrollment.course?.title || 'Unknown Course',
      enrolledAt: this.parseLearnWorldsDate(enrollment.enrolled_at || enrollment.created || ''),
      status: this.mapLearnWorldsEnrollmentStatus(enrollment),
      progress: progress.percentage,
      completedAt: enrollment.completed_at ? this.parseLearnWorldsDate(enrollment.completed_at) : undefined,
      expiresAt: enrollment.expires_at ? this.parseLearnWorldsDate(enrollment.expires_at) : undefined,
      lastAccessedAt: enrollment.last_accessed_at ? this.parseLearnWorldsDate(enrollment.last_accessed_at) : undefined,
      timeSpent: progress.timeSpent || enrollment.time_spent || 0,
      certificateUrl: enrollment.certificate_url,
      grade: enrollment.grade || enrollment.final_grade,
    };
  }

  /**
   * Calculate enrollment statistics from the enrollment list (pure — no mutation).
   */
  private calculateEnrollmentStats(enrollments: UserDetailEnrollment[]): {
    totalCourses: number;
    completedCourses: number;
    inProgressCourses: number;
    notStartedCourses: number;
    totalTimeSpent: number;
    averageCompletionRate: number;
  } {
    const totalCourses = enrollments.length;
    const completedCourses = enrollments.filter((e) => e.status === 'completed').length;
    const inProgressCourses = enrollments.filter((e) => e.status === 'active' && e.progress > 0 && e.progress < 100).length;
    const notStartedCourses = enrollments.filter((e) => e.status === 'active' && e.progress === 0).length;
    const totalTimeSpent = enrollments.reduce((sum, e) => sum + e.timeSpent, 0);

    let averageCompletionRate = 0;
    const activeEnrollments = enrollments.filter((e) => e.status === 'active' || e.status === 'completed');
    if (activeEnrollments.length > 0) {
      const totalProgress = activeEnrollments.reduce((sum, e) => sum + e.progress, 0);
      averageCompletionRate = Math.round(totalProgress / activeEnrollments.length);
    }

    return { totalCourses, completedCourses, inProgressCourses, notStartedCourses, totalTimeSpent, averageCompletionRate };
  }

  /**
   * Extract statistics from the stats response (pure — no mutation).
   */
  private extractStatistics(stats: LWStatsResponse): Partial<LearnWorldsUserDetailsFull> {
    const result: Partial<LearnWorldsUserDetailsFull> = {};
    if (stats.total_time_spent) {
      result.totalTimeSpent = stats.total_time_spent;
    }
    if (stats.certificates_earned !== undefined) {
      result.totalCertificates = stats.certificates_earned;
    }
    if (stats.badges_earned !== undefined) {
      result.totalBadges = stats.badges_earned;
    }
    if (stats.points !== undefined) {
      result.points = stats.points;
    }
    return result;
  }

  /**
   * Create a summary of user information
   */
  private createUserSummary(userDetails: LearnWorldsUserDetailsFull): Record<string, unknown> {
    const recentActivity = userDetails.enrollments
      ? userDetails.enrollments
          .filter((e) => e.lastAccessedAt)
          .sort((a, b) => (b.lastAccessedAt?.getTime() || 0) - (a.lastAccessedAt?.getTime() || 0))
          .slice(0, 5)
          .map((e) => ({
            courseTitle: e.courseTitle,
            progress: e.progress,
            lastAccessed: e.lastAccessedAt,
          }))
      : [];

    return {
      userId: userDetails.id,
      displayName: userDetails.fullName || userDetails.email,
      status: userDetails.status,
      role: userDetails.role,
      learningProgress: {
        totalCourses: userDetails.totalCourses,
        completedCourses: userDetails.completedCourses,
        inProgressCourses: userDetails.inProgressCourses,
        notStartedCourses: userDetails.notStartedCourses,
        averageCompletionRate: userDetails.averageCompletionRate,
        totalTimeSpent: this.formatDuration(userDetails.totalTimeSpent),
      },
      achievements: {
        certificates: userDetails.totalCertificates,
        badges: userDetails.totalBadges,
        points: userDetails.points,
        level: userDetails.level,
      },
      engagement: {
        accountAge: Math.floor((new Date().getTime() - userDetails.createdAt.getTime()) / (1000 * 60 * 60 * 24)),
        lastLoginDaysAgo: userDetails.lastLoginAt ? Math.floor((new Date().getTime() - userDetails.lastLoginAt.getTime()) / (1000 * 60 * 60 * 24)) : null,
        lastActivityDaysAgo: userDetails.lastActivityDate
          ? Math.floor((new Date().getTime() - userDetails.lastActivityDate.getTime()) / (1000 * 60 * 60 * 24))
          : null,
      },
      recentActivity,
    };
  }

  /**
   * Define the parameters for this action
   */
  public get Params(): ActionParam[] {
    const baseParams = this.getCommonLMSParams();

    const specificParams: ActionParam[] = [
      {
        Name: 'UserID',
        Type: 'Input',
        Value: null,
      },
      {
        Name: 'IncludeEnrollments',
        Type: 'Input',
        Value: true,
      },
      {
        Name: 'IncludeStats',
        Type: 'Input',
        Value: true,
      },
    ];

    return [...baseParams, ...specificParams];
  }
}
