import { Router, Request, Response, NextFunction } from 'express';
import mjml2html from 'mjml';
import { load as loadHtml } from 'cheerio';
import { query, queryOne } from '../db';

const router = Router();

interface TemplateRow {
  id: string;
  name: string;
  grapesjs_json: Record<string, unknown> | null;
  compiled_html: string | null;
  thumbnail_url: string | null;
  created_at: string;
  updated_at: string;
}

function isEmptyProjectJson(value: Record<string, unknown> | null): boolean {
  if (!value) return true;
  return Object.keys(value).length === 0;
}

function isLegacyRepairV1(value: Record<string, unknown> | null): boolean {
  if (!value) return false;
  return value.source === 'legacy-compiled-html' && value.schema_version === 1;
}

function createLegacyProjectJson(compiledHtml: string): Record<string, unknown> {
  const $ = loadHtml(compiledHtml);
  const bodyHtml = $('body').html()?.trim() || compiledHtml;

  return {
    schema_version: 2,
    source: 'legacy-compiled-html-project',
    legacy_compiled_html: compiledHtml,
    styles: [],
    assets: [],
    pages: [
      {
        id: 'legacy-main',
        name: 'Main',
        frames: [
          {
            component: bodyHtml,
          },
        ],
      },
    ],
  };
}

// GET /api/templates
router.get('/', async (_req: Request, res: Response, next: NextFunction) => {
  try {
    const templates = await query('SELECT id, name, thumbnail_url, created_at, updated_at FROM templates ORDER BY updated_at DESC');
    res.json(templates);
  } catch (err) { next(err); }
});

// GET /api/templates/:id
router.get('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const template = await queryOne<TemplateRow>('SELECT * FROM templates WHERE id=$1', [req.params.id]);
    if (!template) return res.status(404).json({ error: 'Template not found' });

    const needsBackfill =
      (isEmptyProjectJson(template.grapesjs_json) || isLegacyRepairV1(template.grapesjs_json)) &&
      !!template.compiled_html;

    if (!needsBackfill) {
      return res.json(template);
    }

    const repairedJson = createLegacyProjectJson(template.compiled_html as string);
    const updated = await queryOne<TemplateRow>(
      `UPDATE templates
       SET grapesjs_json=$1, updated_at=now()
       WHERE id=$2
       RETURNING *`,
      [JSON.stringify(repairedJson), req.params.id]
    );

    res.json(updated ?? { ...template, grapesjs_json: repairedJson });
  } catch (err) { next(err); }
});

// POST /api/templates
router.post('/', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { name, grapesjs_json, compiled_html } = req.body;
    const template = await queryOne(
      `INSERT INTO templates (name, grapesjs_json, compiled_html)
       VALUES ($1,$2,$3) RETURNING *`,
      [name, grapesjs_json ? JSON.stringify(grapesjs_json) : null, compiled_html || null]
    );
    res.status(201).json(template);
  } catch (err) { next(err); }
});

// PATCH /api/templates/:id
router.patch('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { name, grapesjs_json, compiled_html, thumbnail_url } = req.body;
    const template = await queryOne(
      `UPDATE templates SET name=$1, grapesjs_json=$2, compiled_html=$3,
       thumbnail_url=$4, updated_at=now() WHERE id=$5 RETURNING *`,
      [name, grapesjs_json ? JSON.stringify(grapesjs_json) : null, compiled_html || null, thumbnail_url || null, req.params.id]
    );
    if (!template) return res.status(404).json({ error: 'Template not found' });
    res.json(template);
  } catch (err) { next(err); }
});

// DELETE /api/templates/:id
router.delete('/:id', async (req: Request, res: Response, next: NextFunction) => {
  try {
    await query('DELETE FROM templates WHERE id=$1', [req.params.id]);
    res.status(204).send();
  } catch (err) { next(err); }
});

// POST /api/templates/compile — MJML → HTML
router.post('/compile', async (req: Request, res: Response, next: NextFunction) => {
  try {
    const { mjml } = req.body;
    if (!mjml) return res.status(400).json({ error: 'mjml string required' });
    const result = mjml2html(mjml, { validationLevel: 'soft' });
    res.json({ html: result.html, errors: result.errors });
  } catch (err) { next(err); }
});

export default router;
