import { Expose, Type } from "class-transformer";
import { ArrayMaxSize, IsArray, IsBoolean, IsDateString, IsEmail, IsEnum, IsIn, IsNotEmpty, IsNumber, IsOptional, IsString, Max, MaxLength, Min, ValidateNested } from "class-validator";
import { ReviewDecision, SubmissionSource, SubmissionStatus } from "../../constants.js";
import { ToNumber } from "../../utils/toNumber.js";

export class SubmissionLinkDto {
    @Expose()
    @IsString()
    @IsNotEmpty()
    url!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    label!: string;
}

export class SubmissionFileDto {
    @Expose()
    @IsString()
    @IsNotEmpty()
    fileId!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    url!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    name!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    mimeType!: string;

    @Expose()
    @ToNumber()
    @IsNumber()
    @IsNotEmpty()
    sizeBytes!: number;
}

export class SubmissionImageDto {
    @Expose()
    @IsString()
    @IsNotEmpty()
    fileId!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    url!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    name!: string;
}

export class SubmissionPayloadDto {
    @Expose()
    @IsOptional()
    @IsString()
    @MaxLength(5000)
    textResponse?: string;

    @Expose()
    @IsOptional()
    @IsArray()
    @ValidateNested({ each: true })
    @Type(() => SubmissionLinkDto)
    @ArrayMaxSize(20)
    links?: SubmissionLinkDto[];

    @Expose()
    @IsOptional()
    @IsArray()
    @ValidateNested({ each: true })
    @Type(() => SubmissionFileDto)
    files?: SubmissionFileDto[];

    @Expose()
    @IsOptional()
    @IsArray()
    @ValidateNested({ each: true })
    @Type(() => SubmissionImageDto)
    images?: SubmissionImageDto[];
}

export class CreateOrUpdateHpActivitySubmissionBodyDto {
    @Expose()
    @IsString()
    @IsNotEmpty()
    courseId!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    courseVersionId!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    cohortId!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    activityId!: string;

    @Expose()
    @ValidateNested()
    @Type(() => SubmissionPayloadDto)
    payload!: SubmissionPayloadDto;

    @Expose()
    @IsOptional()
    @IsEnum(["CSV_IMPORT", "IN_PLATFORM", "VIBE_AUTO"])
    submissionSource?: SubmissionSource;
}


export class ReviewHpActivitySubmissionBodyDto {
    @Expose()
    @IsString()
    @IsIn(["APPROVED", "REJECTED", "REVERTED"])
    decision!: ReviewDecision;

    @Expose()
    @IsOptional()
    @IsString()
    @MaxLength(1000)
    note?: string;

    @Expose()
    @IsOptional()
    @IsNumber()
    pointsToDeduct: number;
}

export class SubmissionFeedbackDto {
    @Expose()
    @IsString()
    feedback!: string;

    @Expose()
    @IsString()
    username!: string;

    @Expose()
    @IsString()
    email!: string;

    @Expose()
    @IsDateString()
    feedbackAt!: Date;
}

export class SubmissionFeedbackBody {
    @Expose()
    @IsString()
    @MaxLength(1000)
    feedback: string;
}

export class ListSubmissionsQueryDto {
    @Expose()
    @IsOptional()
    @ToNumber()
    @IsNumber()
    @Min(1)
    page?: number;

    @Expose()
    @IsOptional()
    @ToNumber()
    @IsNumber()
    @Min(1)
    limit?: number;

    @Expose()
    @IsOptional()
    @IsString()
    search?: string;

    @Expose()
    @IsOptional()
    @IsString()
    courseVersionId?: string;

    @Expose()
    @IsOptional()
    @IsString()
    cohortId?: string;

    @Expose()
    @IsOptional()
    @IsString()
    activityId?: string;

    @Expose()
    @IsOptional()
    @IsString()
    @IsIn(["SUBMITTED", "APPROVED", "REJECTED", "REVERTED"])
    status?: SubmissionStatus;

    @Expose()
    @IsOptional()
    @IsString()
    sortBy?: string;

    @Expose()
    @IsOptional()
    @IsString()
    @IsIn(["asc", "desc"])
    sortOrder?: "asc" | "desc";
}



export class FilterQueryDto {
    @Expose()
    @IsOptional()
    @ToNumber()
    @IsNumber()
    @Min(1)
    page?: number;

    @Expose()
    @IsOptional()
    @ToNumber()
    @IsNumber()
    @Min(1)
    limit?: number;

    @Expose()
    @IsOptional()
    @IsString()
    search?: string;

    @Expose()
    @IsOptional()
    @IsString()
    sortBy?: string;

    @Expose()
    @IsOptional()
    @IsString()
    @IsIn(["asc", "desc"])
    sortOrder?: "asc" | "desc";
}



export class StudentSubmissionActivityDto {
    @Expose()
    @IsString()
    id!: string;

    @Expose()
    @IsString()
    title!: string;

    @Expose()
    @IsString()
    description!: string;

    @Expose()
    @IsString()
    activityType!: string;
}

export class SubmissionAttachmentsDto {
    @Expose()
    @IsString()
    textResponse!: string;

    @Expose()
    @Type(() => SubmissionLinkDto)
    @IsArray()
    links!: SubmissionLinkDto[];

    @Expose()
    @Type(() => SubmissionFileDto)
    @IsArray()
    files!: SubmissionFileDto[];

    @Expose()
    @Type(() => SubmissionFileDto)
    @IsArray()
    images!: SubmissionFileDto[];
}

export class StudentSubmissionDto {
    @Expose()
    @IsString()
    _id!: string;

    @Expose()
    @IsString()
    status!: string;

    @Expose()
    @IsOptional()
    @IsDateString()
    submittedAt!: Date | null;

    @Expose()
    @IsBoolean()
    isLate!: boolean;

    @Expose()
    @Type(() => SubmissionAttachmentsDto)
    attachments!: SubmissionAttachmentsDto;
}

export class SubmissionHpDto {
    @Expose()
    @IsNumber()
    baseHp!: number;

    @Expose()
    @IsNumber()
    currentHp!: number;
}

export class InstructorFeedbackDto {
    @Expose()
    @IsString()
    reviewedBy!: string;

    @Expose()
    @IsOptional()
    @IsEmail()
    reviewerEmail?: string | null;

    @Expose()
    @IsOptional()
    @IsString()
    reviewerName?: string | null;

    @Expose()
    @IsDateString()
    reviewedAt!: Date;

    @Expose()
    @IsString()
    decision!: string;

    @Expose()
    @IsString()
    note!: string;
}

export class StudentActivitySubmissionsViewDto {

    @Expose()
    @Type(() => StudentSubmissionActivityDto)
    activity!: StudentSubmissionActivityDto;

    @Expose()
    @IsString()
    courseId!: string;

    @Expose()
    @IsDateString()
    deadline!: Date;

    @Expose()
    @Type(() => StudentSubmissionDto)
    submission!: StudentSubmissionDto;

    @Expose()
    @Type(() => SubmissionHpDto)
    hp!: SubmissionHpDto;

    @Expose()
    @IsOptional()
    @Type(() => InstructorFeedbackDto)
    instructorFeedback!: InstructorFeedbackDto | null;

    @Expose()
    @IsOptional()
    @Type(() => SubmissionFeedbackDto)
    @IsArray()
    feedbacks!: SubmissionFeedbackDto[];

    @Expose()
    @IsString()
    isRequiredInstructorApproval!: boolean;
}

export class PaginationMetaDto {
    @Expose()
    @IsNumber()
    total!: number;

    @Expose()
    @IsNumber()
    page!: number;

    @Expose()
    @IsNumber()
    limit!: number;
}

export class StudentActivitySubmissionsResponseDto {

    @Expose()
    @IsBoolean()
    success!: boolean;

    @Expose()
    @Type(() => StudentActivitySubmissionsViewDto)
    @IsArray()
    data!: StudentActivitySubmissionsViewDto[];

    @Expose()
    @Type(() => PaginationMetaDto)
    @IsOptional()
    meta?: PaginationMetaDto;
}

export class RewardInfoDto {
    @Expose()
    @IsString()
    @IsIn(["ABSOLUTE", "PERCENTAGE"])
    type!: string;

    @Expose()
    @IsNumber()
    value!: number;
}

export class CoursePerformanceDto {
    @Expose()
    @IsString()
    courseId!: string;

    @Expose()
    @IsString()
    courseName!: string;

    @Expose()
    @IsNumber()
    totalHp!: number;

    @Expose()
    @IsNumber()
    studentCount!: number;
}

export class WeeklyActivityDto {
    @Expose()
    @IsString()
    date!: string;

    @Expose()
    @IsNumber()
    studentCount!: number;
}

export class StudentActivitySubmissionStatsViewDto {
    @Expose()
    @IsNumber()
    totalActivities!: number;
    @Expose()
    @IsNumber()
    totalSubmissions!: number;
    @Expose()
    @IsNumber()
    totalPendings!: number;
    @Expose()
    @IsNumber()
    totalLateSubmissions!: number;
    @Expose()
    @IsNumber()
    currentHp!: number;
    @Expose()
    @IsOptional()
    @Type(() => RewardInfoDto)
    reward?: RewardInfoDto | null;

    // Dashboard metrics
    @Expose()
    @IsNumber()
    totalStudents?: number;

    @Expose()
    @IsString()
    bestPerformingCohort!: string;

    @Expose()
    @IsArray()
    @Type(() => CoursePerformanceDto)
    coursePerformance!: CoursePerformanceDto[];

    @Expose()
    @IsArray()
    @Type(() => WeeklyActivityDto)
    weeklyActivity!: WeeklyActivityDto[];
}

export class StudentActivitySubmissionStatsResponseDto {

    @Expose()
    @IsBoolean()
    success!: boolean;

    @Expose()
    data!: StudentActivitySubmissionStatsViewDto
}

export class StudentCohortWiseActivitySubmissionsStatsDto {
    @Expose()
    data!: {
        totalSubmissions: number;
        approvedCount: number;
        rejectedCount: number;
        revertedCount: number;
        submittedCount: number;
    };
}

// ─── Student Dashboard Stats DTOs ─────────────────────────────────────────

export class StudentDashboardStatsQueryDto {
    @Expose()
    @IsString()
    @IsNotEmpty()
    cohortName!: string;

    @Expose()
    @IsString()
    @IsNotEmpty()
    courseVersionId!: string;

    @Expose()
    @IsOptional()
    @ToNumber()
    @IsNumber()
    @Min(1)
    @Max(30)
    timelineDays?: number = 7;
}

export class MyStatsDto {
    @Expose()
    @IsNumber()
    totalHp!: number;

    @Expose()
    @IsNumber()
    completedActivities!: number;

    @Expose()
    @IsNumber()
    pendingSubmissions!: number;

    @Expose()
    @IsNumber()
    completionPercentage!: number;
}

export class ProgressTimelineItemDto {
    @Expose()
    @IsString()
    date!: string;

    @Expose()
    @IsNumber()
    hpChange!: number;

    @Expose()
    @IsNumber()
    activitiesCompleted!: number;
}

export class ActivityBreakdownDto {
    @Expose()
    @IsNumber()
    notStarted!: number;

    @Expose()
    @IsNumber()
    submitted!: number;

    @Expose()
    @IsNumber()
    approved!: number;

    @Expose()
    @IsNumber()
    rejected!: number;
}

export class UpcomingDeadlineDto {
    @Expose()
    @IsString()
    activityTitle!: string;

    @Expose()
    @IsString()
    deadlineDate!: string;

    @Expose()
    @IsNumber()
    daysLeft!: number;
}

export class RecentSubmissionDto {
    @Expose()
    @IsString()
    activityTitle!: string;

    @Expose()
    @IsString()
    submittedAt!: string;

    @Expose()
    @IsString()
    status!: string;

    @Expose()
    @IsNumber()
    hpEarned!: number;
}

export class StudentDashboardStatsDataDto {
    @Expose()
    @Type(() => MyStatsDto)
    myStats!: MyStatsDto;

    @Expose()
    @IsArray()
    @Type(() => ProgressTimelineItemDto)
    progressTimeline!: ProgressTimelineItemDto[];

    @Expose()
    @Type(() => ActivityBreakdownDto)
    activityBreakdown!: ActivityBreakdownDto;

    @Expose()
    @IsArray()
    @Type(() => UpcomingDeadlineDto)
    upcomingDeadlines!: UpcomingDeadlineDto[];

    @Expose()
    @IsArray()
    @Type(() => RecentSubmissionDto)
    recentSubmissions!: RecentSubmissionDto[];
}

export class StudentDashboardStatsResponseDto {
    @Expose()
    @IsBoolean()
    success!: boolean;

    @Expose()
    @Type(() => StudentDashboardStatsDataDto)
    data!: StudentDashboardStatsDataDto;
}