import type { CertificatePayload, CertificationTrack, ScoreBreakdown, ValidationSummary } from '../_types.js'; import { getSupabaseAdmin, getSupabaseClientForRequest } from '../_shared/supabaseAdmin.js'; function makeCertificateId(skill: string, track: CertificationTrack = 'verifiedcert'): string { const date = new Date(); const y = date.getUTCFullYear(); const m = String(date.getUTCMonth() + 1).padStart(2, '0'); const d = String(date.getUTCDate()).padStart(2, '0'); const suffix = Math.random().toString(36).slice(2, 10).toUpperCase(); const normalizedSkill = skill.replace(/[^a-zA-Z0-9]/g, '').slice(0, 6).toUpperCase() || 'SKILL'; const prefix = track === 'free_completion' ? 'FC' : track === 'quickcert' ? 'QC' : track === 'ytcert' ? 'YT' : 'VC'; return `${prefix}-${normalizedSkill}-${y}${m}${d}-${suffix}`; } export async function issueCertificate(input: { userId: string; name: string; email: string; skill: string; projectTitle: string; githubUrl: string; proofUrl: string; liveDemoUrl?: string; finalScore?: number; scoreBreakdown?: ScoreBreakdown; validationSummary?: ValidationSummary; projectType?: string; commitCount?: number; paymentRequestId?: string; paymentTxnId?: string | null; extraMetadata?: Record; authToken?: string | null; track?: CertificationTrack; }): Promise { const serviceRoleKey = process.env.SUPABASE_SERVICE_ROLE_KEY; const supabase = (!input.authToken && serviceRoleKey) ? getSupabaseAdmin() : getSupabaseClientForRequest(input.authToken); const certTrack = input.track || 'verifiedcert'; if (input.paymentRequestId) { const { data: existing } = await supabase .from('certificates') .select('user_id, topic, project_title, issued_at, metadata') .eq('metadata->>payment_request_id', input.paymentRequestId) .order('issued_at', { ascending: false }) .limit(1) .maybeSingle(); if (existing) { return { certificateId: (existing.metadata as any)?.certificate_id || makeCertificateId(existing.topic || input.skill, certTrack), userId: existing.user_id, name: (existing.metadata as any)?.username || (existing as any).username || input.name, skill: existing.topic, projectTitle: existing.project_title || input.projectTitle, githubUrl: (existing.metadata as any)?.github_repo_url || (existing.metadata as any)?.github_url || input.githubUrl, proofUrl: (existing.metadata as any)?.live_demo_url || (existing.metadata as any)?.proof_url || input.proofUrl, issuedAt: existing.issued_at, track: certTrack, }; } } const certificateId = makeCertificateId(input.skill, certTrack); const payload: CertificatePayload = { certificateId, userId: input.userId, name: input.name, skill: input.skill, projectTitle: input.projectTitle, githubUrl: input.githubUrl, proofUrl: input.proofUrl, issuedAt: new Date().toISOString(), track: certTrack, }; const normalizedScoreBreakdown = input.scoreBreakdown ? { interview_score: input.scoreBreakdown.interviewScore, github_validation_score: input.scoreBreakdown.githubValidationScore, proof_validation_score: input.scoreBreakdown.proofValidationScore, commit_score: input.scoreBreakdown.commitScore, structure_score: input.scoreBreakdown.structureScore, readme_score: input.scoreBreakdown.readmeScore, } : null; const normalizedValidationSummary = input.validationSummary ? { overall_passed: input.validationSummary.overallPassed, commit_passed: input.validationSummary.commitPassed, readme_passed: input.validationSummary.readmePassed, proof_passed: input.validationSummary.proofPassed, commit_count: input.validationSummary.commitCount, file_count: input.validationSummary.fileCount, meaningful_file_count: input.validationSummary.meaningfulFileCount, readme_richness: input.validationSummary.readmeRichness, suspicious_signals: input.validationSummary.suspiciousSignals, } : null; const { error } = await supabase.from('certificates').insert({ user_id: input.userId, topic: input.skill, project_title: input.projectTitle, metadata: { certificate_id: certificateId, username: input.name, email: input.email, course_topic: input.skill, project_topic: input.projectTitle, github_repo_url: input.githubUrl, live_demo_url: input.liveDemoUrl || input.proofUrl, final_score: input.finalScore ?? null, score_breakdown: normalizedScoreBreakdown, project_type: input.projectType || null, commit_count: input.commitCount ?? null, validation_summary: normalizedValidationSummary, github_url: input.githubUrl, proof_url: input.proofUrl, getcert_version: 'v2', certification_track: certTrack, payment_request_id: input.paymentRequestId || null, payment_txn_id: input.paymentTxnId || null, ...(input.extraMetadata || {}), }, issued_at: payload.issuedAt, }); if (error) { throw new Error(`Failed to issue certificate: ${error.message}`); } return payload; }