import puppeteer from 'puppeteer';
import path from 'path';
import fs from 'fs/promises';
import crypto from 'crypto';
import { db } from '../../config/database.js';
import { registracie, ucastnici, kurzy, prilohy } from '../../db/schema.js';
import { eq, and } from 'drizzle-orm';
import { NotFoundError } from '../../utils/errors.js';
import { logger } from '../../utils/logger.js';

const UPLOAD_DIR = path.join(process.cwd(), 'uploads', 'ai-kurzy', 'certificates');
const ASSETS_DIR = path.join(process.cwd(), 'src', 'assets', 'certificate');
const TEMPLATES_DIR = path.join(process.cwd(), 'src', 'templates', 'certificates');

/**
 * Available certificate templates
 */
export const CERTIFICATE_TEMPLATES = {
  AIcertifikat: {
    name: 'AI Certifikát',
    file: 'AIcertifikat.html',
    description: 'Osvedčenie o absolvovaní AI kurzu',
    background: 'background.jpeg',
  },
  ScrumGeneric: {
    name: 'Scrum (Gablas)',
    file: 'ScrumGeneric.html',
    description: 'Scrum Master / Product Owner - lektor Gablas',
    background: 'background-blue.jpeg',
  },
  ITIL: {
    name: 'ITIL (Husam)',
    file: 'ITIL.html',
    description: 'ITIL Foundation - lektor Husam',
    background: 'background-green.jpeg',
  },
  PRINCE2: {
    name: 'PRINCE2 (Gablas)',
    file: 'PRINCE2.html',
    description: 'PRINCE2 Foundation/Practitioner - lektor Gablas',
    background: 'background-orange.jpeg',
  },
};

/**
 * Format date to Slovak format (DD.MM.YYYY)
 */
const formatDate = (date) => {
  if (!date) return '';
  const d = new Date(date);
  return d.toLocaleDateString('sk-SK', {
    day: '2-digit',
    month: '2-digit',
    year: 'numeric',
  });
};

/**
 * Generate unique certificate ID
 */
const generateCertificateId = (registraciaId) => {
  const hash = crypto.createHash('sha256')
    .update(`${registraciaId}-${Date.now()}`)
    .digest('hex')
    .substring(0, 8)
    .toUpperCase();
  return `CERT-${hash}`;
};

/**
 * Load assets as base64 for embedding in HTML
 */
const loadAssets = async (templateName) => {
  const template = CERTIFICATE_TEMPLATES[templateName];
  const backgroundFile = template?.background || 'background.jpeg';

  const [background, signatureGablasova, signatureZdarilek] = await Promise.all([
    fs.readFile(path.join(ASSETS_DIR, backgroundFile)),
    fs.readFile(path.join(ASSETS_DIR, 'signature-gablasova.png')),
    fs.readFile(path.join(ASSETS_DIR, 'signature-zdarilek.png')),
  ]);

  return {
    backgroundImage: `data:image/jpeg;base64,${background.toString('base64')}`,
    signatureGablasova: `data:image/png;base64,${signatureGablasova.toString('base64')}`,
    signatureZdarilek: `data:image/png;base64,${signatureZdarilek.toString('base64')}`,
  };
};

/**
 * Load HTML template from file
 */
const loadTemplate = async (templateName) => {
  const template = CERTIFICATE_TEMPLATES[templateName];
  if (!template) {
    throw new NotFoundError(`Šablóna "${templateName}" neexistuje`);
  }

  const templatePath = path.join(TEMPLATES_DIR, template.file);
  try {
    return await fs.readFile(templatePath, 'utf-8');
  } catch (error) {
    throw new NotFoundError(`Súbor šablóny "${template.file}" nenájdený`);
  }
};

/**
 * Replace template placeholders with actual values
 * Supports {{variable}} and {{#if variable}}...{{/if}} syntax
 */
const renderTemplate = (template, data) => {
  let html = template;

  // Handle conditional blocks {{#if variable}}...{{/if}}
  html = html.replace(/\{\{#if\s+(\w+)\}\}([\s\S]*?)\{\{\/if\}\}/g, (match, variable, content) => {
    return data[variable] ? content : '';
  });

  // Replace simple placeholders {{variable}}
  html = html.replace(/\{\{(\w+)\}\}/g, (match, variable) => {
    return data[variable] !== undefined ? data[variable] : '';
  });

  return html;
};

/**
 * Get list of available templates
 */
export const getAvailableTemplates = () => {
  return Object.entries(CERTIFICATE_TEMPLATES).map(([key, value]) => ({
    id: key,
    name: value.name,
    description: value.description,
  }));
};

/**
 * Check if certificate already exists for registration
 */
export const hasCertificate = async (registraciaId) => {
  const [existing] = await db
    .select({ id: prilohy.id })
    .from(prilohy)
    .where(and(
      eq(prilohy.registraciaId, registraciaId),
      eq(prilohy.typPrilohy, 'certifikat')
    ))
    .limit(1);

  return !!existing;
};

/**
 * Generate certificate PDF for a registration
 * @param {number} registraciaId - Registration ID
 * @param {string} templateName - Template name (default: 'AIcertifikat')
 */
export const generateCertificate = async (registraciaId, templateName = 'AIcertifikat') => {
  // Check if certificate already exists
  const exists = await hasCertificate(registraciaId);
  if (exists) {
    throw new Error('Certifikát pre túto registráciu už existuje');
  }

  // Fetch registration with participant and course data
  const [registration] = await db
    .select({
      id: registracie.id,
      ucastnikId: registracie.ucastnikId,
      kurzId: registracie.kurzId,
    })
    .from(registracie)
    .where(eq(registracie.id, registraciaId))
    .limit(1);

  if (!registration) {
    throw new NotFoundError('Registrácia nenájdená');
  }

  // Fetch participant
  const [participant] = await db
    .select({
      titul: ucastnici.titul,
      meno: ucastnici.meno,
      priezvisko: ucastnici.priezvisko,
    })
    .from(ucastnici)
    .where(eq(ucastnici.id, registration.ucastnikId))
    .limit(1);

  if (!participant) {
    throw new NotFoundError('Účastník nenájdený');
  }

  // Fetch course
  const [course] = await db
    .select({
      nazov: kurzy.nazov,
      popis: kurzy.popis,
      datumOd: kurzy.datumOd,
      datumDo: kurzy.datumDo,
    })
    .from(kurzy)
    .where(eq(kurzy.id, registration.kurzId))
    .limit(1);

  if (!course) {
    throw new NotFoundError('Kurz nenájdený');
  }

  // Load template and assets
  const [templateHtml, assets] = await Promise.all([
    loadTemplate(templateName),
    loadAssets(templateName),
  ]);

  // Generate certificate data
  const certificateId = generateCertificateId(registraciaId);
  const participantName = [participant.titul, participant.meno, participant.priezvisko]
    .filter(Boolean)
    .join(' ');

  const issueDate = course.datumDo || course.datumOd || new Date();

  // Format date range
  let dateRange = '';
  if (course.datumOd && course.datumDo) {
    dateRange = `${formatDate(course.datumOd)} - ${formatDate(course.datumDo)}`;
  } else if (course.datumDo) {
    dateRange = formatDate(course.datumDo);
  } else if (course.datumOd) {
    dateRange = formatDate(course.datumOd);
  }

  // Prepare template data
  const templateData = {
    participantName,
    courseTitle: course.nazov,
    courseModules: course.popis || '',
    dateRange,
    issueDate: formatDate(issueDate),
    certificateId,
    ...assets,
  };

  // Render template with data
  const html = renderTemplate(templateHtml, templateData);

  // Ensure upload directory exists
  await fs.mkdir(UPLOAD_DIR, { recursive: true });

  // Generate filename
  const safeName = participantName
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-zA-Z0-9 ]/g, '')
    .replace(/\s+/g, '_');
  const fileName = `certifikat_${safeName}_${certificateId}.pdf`;
  const filePath = path.join(UPLOAD_DIR, fileName);

  // Launch Puppeteer and generate PDF
  let browser;
  try {
    browser = await puppeteer.launch({
      headless: true,
      args: ['--no-sandbox', '--disable-setuid-sandbox'],
    });

    const page = await browser.newPage();
    await page.setContent(html, { waitUntil: 'networkidle0' });

    await page.pdf({
      path: filePath,
      width: '297mm',
      height: '210mm',
      printBackground: true,
      margin: { top: 0, right: 0, bottom: 0, left: 0 },
    });

    logger.info(`Certificate generated: ${fileName} (template: ${templateName})`);
  } finally {
    if (browser) {
      await browser.close();
    }
  }

  // Get file stats
  const stats = await fs.stat(filePath);

  // Save as priloha (attachment)
  const [attachment] = await db
    .insert(prilohy)
    .values({
      registraciaId,
      nazovSuboru: fileName,
      typPrilohy: 'certifikat',
      cestaKSuboru: filePath,
      mimeType: 'application/pdf',
      velkostSuboru: stats.size,
      popis: `Certifikát vygenerovaný ${formatDate(new Date())} - ${certificateId} (šablóna: ${templateName})`,
    })
    .returning();

  return {
    id: attachment.id,
    fileName,
    filePath,
    certificateId,
    participantName,
    courseTitle: course.nazov,
    templateUsed: templateName,
  };
};

/**
 * Get certificate download info
 */
export const getCertificateDownloadInfo = async (prilohaId) => {
  const [attachment] = await db
    .select()
    .from(prilohy)
    .where(eq(prilohy.id, prilohaId))
    .limit(1);

  if (!attachment) {
    throw new NotFoundError('Certifikát nenájdený');
  }

  // Check if file exists
  try {
    await fs.access(attachment.cestaKSuboru);
  } catch {
    throw new NotFoundError('Súbor certifikátu nenájdený na serveri');
  }

  return {
    filePath: attachment.cestaKSuboru,
    fileName: attachment.nazovSuboru,
    mimeType: attachment.mimeType,
  };
};
