import { Injectable, NotFoundException } from '@nestjs/common';
import { AssessmentType, AssignmentStatus } from '@prisma/client';
import { PrismaService } from '../prisma/prisma.service';

@Injectable()
export class ReportsService {
  constructor(private readonly prisma: PrismaService) {}

  async monthlySummary(periodMonth?: number, periodYear?: number) {
    return this.summaryByType(AssessmentType.MONTHLY, periodMonth, periodYear);
  }

  async annualSummary(periodYear?: number) {
    return this.summaryByType(AssessmentType.ANNUAL, undefined, periodYear);
  }

  async pendingSubmissions(periodMonth?: number, periodYear?: number) {
    return this.prisma.assessmentAssignment.findMany({
      where: {
        deletedAt: null,
        status: {
          in: [AssignmentStatus.PENDING, AssignmentStatus.DRAFT, AssignmentStatus.REOPENED],
        },
        campaign: {
          deletedAt: null,
          ...(periodMonth ? { periodMonth } : {}),
          ...(periodYear ? { periodYear } : {}),
        },
      },
      include: {
        employee: true,
        campaign: true,
      },
      orderBy: [{ campaign: { periodYear: 'desc' } }, { campaign: { periodMonth: 'desc' } }],
    });
  }

  async employeeHistory(employeeId: string) {
    const user = await this.prisma.user.findUnique({
      where: { id: employeeId },
      include: { role: true, department: true, manager: true },
    });
    if (!user) {
      throw new NotFoundException('Employee not found');
    }

    const history = await this.prisma.assessmentAssignment.findMany({
      where: {
        employeeId,
        deletedAt: null,
      },
      include: {
        campaign: true,
        submissions: {
          include: {
            answers: {
              include: { question: true },
            },
          },
        },
      },
      orderBy: [{ campaign: { periodYear: 'desc' } }, { campaign: { periodMonth: 'desc' } }],
    });

    return {
      employee: user,
      history,
    };
  }

  async exportMonthly(periodMonth?: number, periodYear?: number) {
    const summary = await this.monthlySummary(periodMonth, periodYear);
    return this.buildExportPayload(summary.campaigns);
  }

  async exportAnnual(periodYear?: number) {
    const summary = await this.annualSummary(periodYear);
    return this.buildExportPayload(summary.campaigns);
  }

  private async summaryByType(
    assessmentType: AssessmentType,
    periodMonth?: number,
    periodYear?: number,
  ) {
    const campaigns = await this.prisma.assessmentCampaign.findMany({
      where: {
        assessmentType,
        deletedAt: null,
        ...(periodMonth ? { periodMonth } : {}),
        ...(periodYear ? { periodYear } : {}),
      },
      include: {
        template: true,
        assignments: {
          where: { deletedAt: null },
          include: {
            employee: true,
            submissions: true,
          },
        },
      },
      orderBy: [{ periodYear: 'desc' }, { periodMonth: 'desc' }, { createdAt: 'desc' }],
    });

    return campaigns.reduce(
      (acc, campaign) => {
        const pendingStatuses = new Set<AssignmentStatus>([
          AssignmentStatus.PENDING,
          AssignmentStatus.DRAFT,
          AssignmentStatus.REOPENED,
        ]);
        const totalAssignments = campaign.assignments.length;
        const submitted = campaign.assignments.filter(
          (assignment) => assignment.status === AssignmentStatus.SUBMITTED,
        ).length;
        const pending = campaign.assignments.filter((assignment) =>
          pendingStatuses.has(assignment.status),
        ).length;
        const locked = campaign.assignments.filter(
          (assignment) => assignment.status === AssignmentStatus.LOCKED,
        ).length;
        const missed = campaign.assignments.filter(
          (assignment) => assignment.status === AssignmentStatus.MISSED,
        ).length;

        acc.totalCampaigns += 1;
        acc.totalAssignments += totalAssignments;
        acc.submitted += submitted;
        acc.pending += pending;
        acc.locked += locked;
        acc.missed += missed;
        acc.campaigns.push({
          id: campaign.id,
          title: campaign.title,
          assessmentType: campaign.assessmentType,
          periodMonth: campaign.periodMonth,
          periodYear: campaign.periodYear,
          status: campaign.status,
          templateName: campaign.template.name,
          totalAssignments,
          submitted,
          pending,
          locked,
          missed,
          submissionRate:
            totalAssignments === 0 ? 0 : Number(((submitted / totalAssignments) * 100).toFixed(2)),
        });
        return acc;
      },
      {
        totalCampaigns: 0,
        totalAssignments: 0,
        submitted: 0,
        pending: 0,
        locked: 0,
        missed: 0,
        campaigns: [] as Array<Record<string, unknown>>,
      },
    );
  }

  private buildExportPayload(campaigns: Array<Record<string, unknown>>) {
    return {
      headers: [
        'title',
        'assessmentType',
        'periodMonth',
        'periodYear',
        'status',
        'templateName',
        'totalAssignments',
        'submitted',
        'pending',
        'locked',
        'missed',
        'submissionRate',
      ],
      rows: campaigns.map((campaign) => ({
        title: campaign.title,
        assessmentType: campaign.assessmentType,
        periodMonth: campaign.periodMonth,
        periodYear: campaign.periodYear,
        status: campaign.status,
        templateName: campaign.templateName,
        totalAssignments: campaign.totalAssignments,
        submitted: campaign.submitted,
        pending: campaign.pending,
        locked: campaign.locked,
        missed: campaign.missed,
        submissionRate: campaign.submissionRate,
      })),
    };
  }
}
