import { db } from "@/lib/prisma";
import { isFinalExam, parseLessonDescriptionMeta } from "@/lib/courses/lessonContent";

type CertificatePrismaClient = {
  certificate: {
    create: (args: object) => Promise<{ id: string; certificateNumber?: string }>;
    findFirst: (args: object) => Promise<{ id: string; certificateNumber?: string } | null>;
  };
};

export type CertificateIssueResult = {
  certificateId: string | null;
  certificateNumber: string | null;
  newlyIssued: boolean;
};

function getText(value: unknown): string {
  if (!value) return "";
  if (typeof value === "string") return value;
  if (typeof value === "object") {
    const record = value as Record<string, unknown>;
    if (typeof record.en === "string") return record.en;
    if (typeof record.es === "string") return record.es;
  }
  return "";
}

function escapePdfText(value: string): string {
  return value.replace(/\\/g, "\\\\").replace(/\(/g, "\\(").replace(/\)/g, "\\)");
}

function buildMinimalPdf(lines: string[]): Uint8Array {
  const contentLines = lines
    .map((line, index) => `BT /F1 14 Tf 72 ${730 - index * 24} Td (${escapePdfText(line)}) Tj ET`)
    .join("\n");
  const stream = `${contentLines}\n`;

  const objects = [
    "1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj",
    "2 0 obj << /Type /Pages /Kids [3 0 R] /Count 1 >> endobj",
    "3 0 obj << /Type /Page /Parent 2 0 R /MediaBox [0 0 612 792] /Resources << /Font << /F1 4 0 R >> >> /Contents 5 0 R >> endobj",
    "4 0 obj << /Type /Font /Subtype /Type1 /BaseFont /Helvetica >> endobj",
    `5 0 obj << /Length ${stream.length} >> stream\n${stream}endstream endobj`,
  ];

  let pdf = "%PDF-1.4\n";
  const offsets: number[] = [0];

  for (const object of objects) {
    offsets.push(pdf.length);
    pdf += `${object}\n`;
  }

  const xrefStart = pdf.length;
  pdf += `xref\n0 ${objects.length + 1}\n`;
  pdf += "0000000000 65535 f \n";
  for (let i = 1; i <= objects.length; i += 1) {
    pdf += `${offsets[i].toString().padStart(10, "0")} 00000 n \n`;
  }
  pdf += `trailer << /Size ${objects.length + 1} /Root 1 0 R >>\nstartxref\n${xrefStart}\n%%EOF`;

  return new TextEncoder().encode(pdf);
}

export async function issueCertificateIfEligible(userId: string, courseId: string): Promise<CertificateIssueResult> {
  const prismaAny = db as unknown as CertificatePrismaClient;
  try {
    const existing = await prismaAny.certificate.findFirst({
      where: { userId, courseId },
      select: { id: true, certificateNumber: true },
    });

    if (existing) {
      return {
        certificateId: existing.id,
        certificateNumber: existing.certificateNumber ?? null,
        newlyIssued: false,
      };
    }

    const [course, completedCount, lessons] = await Promise.all([
      db.course.findUnique({
        where: { id: courseId },
        select: { id: true, title: true, slug: true },
      }),
      db.userProgress.count({
        where: {
          userId,
          isCompleted: true,
          lesson: {
            module: {
              courseId,
            },
          },
        },
      }),
      db.lesson.findMany({
        where: {
          module: {
            courseId,
          },
        },
        select: {
          id: true,
          description: true,
        },
      }),
    ]);

    const totalCount = lessons.length;
    if (!course || totalCount === 0 || completedCount < totalCount) {
      return { certificateId: null, certificateNumber: null, newlyIssued: false };
    }

    const finalExamLessonIds = lessons
      .filter((lesson) => isFinalExam(parseLessonDescriptionMeta(lesson.description).contentType))
      .map((lesson) => lesson.id);

    if (finalExamLessonIds.length > 0) {
      const completedFinalExams = await db.userProgress.count({
        where: {
          userId,
          isCompleted: true,
          lessonId: {
            in: finalExamLessonIds,
          },
        },
      });

      if (completedFinalExams < finalExamLessonIds.length) {
        return { certificateId: null, certificateNumber: null, newlyIssued: false };
      }
    }

    const membership = await db.membership.findFirst({
      where: { userId, isActive: true },
      select: { companyId: true },
    });

    const certificateNumber = `ACVE-${new Date().getFullYear()}-${Math.floor(
      100000 + Math.random() * 900000,
    )}`;

    const certificate = await prismaAny.certificate.create({
      data: {
        userId,
        courseId,
        companyId: membership?.companyId ?? null,
        certificateNumber,
        pdfVersion: 1,
        metadataSnapshot: {
          courseId: course.id,
          courseSlug: course.slug,
          courseTitle: getText(course.title) || "Untitled course",
          certificateNumber,
          completionPercent: 100,
          issuedAt: new Date().toISOString(),
          brandingVersion: "ACVE-2026-01",
        },
      },
      select: { id: true },
    });

    return {
      certificateId: certificate.id,
      certificateNumber: certificate.certificateNumber ?? certificateNumber,
      newlyIssued: true,
    };
  } catch {
    return { certificateId: null, certificateNumber: null, newlyIssued: false };
  }
}

export function buildCertificatePdf(input: {
  certificateNumber: string;
  learnerName: string;
  learnerEmail: string;
  courseTitle: string;
  issuedAt: Date;
}): Uint8Array {
  const date = new Intl.DateTimeFormat("en-US", { dateStyle: "long" }).format(input.issuedAt);

  return buildMinimalPdf([
    "ACVE - Certificate of Completion",
    "",
    `Certificate No: ${input.certificateNumber}`,
    "",
    "This certifies that",
    input.learnerName,
    `(${input.learnerEmail})`,
    "",
    "has successfully completed the course",
    input.courseTitle,
    "",
    `Issued on ${date}`,
  ]);
}
