/**
 * Template Style Routes — Super Admin CRUD
 *
 * Manage famous marketing-style templates that the Landing Page builder can
 * apply. Gated by requireRole('super-admin').
 * Mounted at: /api/super-admin/template-styles
 *
 * IMPORTANT: Literal routes (e.g. /seed) must come BEFORE parameterized routes
 * (e.g. /:id) so Express doesn't match "seed" as an :id parameter.
 */

import { Router, Request, Response } from 'express';
import { getModels } from '../models';
import { authenticate, requireRole } from '../middleware/auth';

const router = Router();

const slugify = (name: string): string =>
  name.toLowerCase().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');

// Character limits — kept in sync with the frontend form (Template Styles page)
// and within the Mongoose schema caps (name maxlength 120, description 500).
const NAME_MAX = 100;
const PROMPT_MAX = 5000;
const DESCRIPTION_MAX = 500;

// Validate editable text fields. Only checks fields that are actually present,
// so it works for both create (full body) and update (partial body).
function validateFields(data: any): string | null {
  if (data.name !== undefined) {
    const name = String(data.name).trim();
    if (name.length < 2) return 'Template name is required (min 2 characters)';
    if (name.length > NAME_MAX) return `Template name cannot exceed ${NAME_MAX} characters`;
  }
  if (data.prompt !== undefined && String(data.prompt).length > PROMPT_MAX) {
    return `Prompt cannot exceed ${PROMPT_MAX} characters`;
  }
  if (data.description !== undefined && String(data.description).length > DESCRIPTION_MAX) {
    return `Description cannot exceed ${DESCRIPTION_MAX} characters`;
  }
  return null;
}

// Find a slug that isn't taken yet, appending -2, -3, … on collision. This lets
// re-imports and duplicate display names always create a fresh record instead of
// failing on the unique-slug index (fixes "import works only once").
async function uniqueSlug(TemplateStyle: any, base: string): Promise<string> {
  let slug = base || 'template';
  let n = 2;
  // eslint-disable-next-line no-await-in-loop
  while (await TemplateStyle.exists({ slug })) {
    slug = `${base}-${n++}`;
  }
  return slug;
}

// Fields a Super Admin may set on a template. Strategy only — templates carry
// no visual styling; branding comes from the company's own brand assets.
const EDITABLE_FIELDS = [
  'name', 'prompt', 'description', 'layoutType', 'conversionFramework', 'pageFlow',
  'copywritingTone', 'heroSectionStyle', 'ctaStyle', 'enabled', 'displayOrder',
];

function pickEditable(data: any): Record<string, any> {
  const out: Record<string, any> = {};
  for (const key of EDITABLE_FIELDS) {
    if (data[key] !== undefined) out[key] = data[key];
  }
  return out;
}

router.use(authenticate);
router.use(requireRole('super-admin'));

// --- List all templates ---
router.get('/', async (req: Request, res: Response) => {
  try {
    const { TemplateStyle } = getModels();
    const { search, enabled } = req.query;
    const filter: any = {};
    if (enabled === 'true') filter.enabled = true;
    if (enabled === 'false') filter.enabled = false;
    if (search) {
      filter.$or = [
        { name: { $regex: search, $options: 'i' } },
        { description: { $regex: search, $options: 'i' } },
      ];
    }
    // Newest first: manual/imported templates default to displayOrder 0 (seeds use
    // 1+), and within the same displayOrder the most recently created wins — so a
    // freshly created record always appears at the top of the list.
    const templates = await TemplateStyle.find(filter).sort({ displayOrder: 1, createdAt: -1 }).lean();
    res.json(templates);
  } catch (error: any) {
    console.error('[SuperAdmin] List template styles error:', error.message);
    res.status(500).json({ error: 'Failed to fetch template styles' });
  }
});

// --- Seed defaults (MUST be before /:id) ---
router.post('/seed', async (_req: Request, res: Response) => {
  try {
    const { seedTemplateStyles } = await import('../utils/seedTemplateStyles');
    const result = await seedTemplateStyles();
    res.json({ message: 'Default template styles seeded', ...result });
  } catch (error: any) {
    console.error('[SuperAdmin] Seed template styles error:', error.message);
    res.status(500).json({ error: 'Failed to seed template styles' });
  }
});

// --- Create ---
router.post('/', async (req: Request, res: Response) => {
  try {
    const { TemplateStyle } = getModels();
    const data = req.body;
    if (!data.name || typeof data.name !== 'string' || data.name.trim().length < 2) {
      res.status(400).json({ error: 'Template name is required (min 2 characters)' });
      return;
    }
    const validationError = validateFields(data);
    if (validationError) {
      res.status(400).json({ error: validationError });
      return;
    }
    // Auto-uniquify the slug instead of rejecting duplicates, so importing the
    // same CSV (or reusing a name) always creates a new record.
    const slug = await uniqueSlug(TemplateStyle, slugify(data.slug || data.name));

    // ── Newest-first ordering (root cause of "new record not at top") ──
    // The list is sorted by { displayOrder: 1, createdAt: -1 }, so displayOrder is
    // the PRIMARY key. Previously every manual/imported record used the schema
    // default (0), so a new record only beat an existing one on the createdAt
    // tie-breaker — fragile (equal-second timestamps, sort direction, etc.). We now
    // assign each new record a displayOrder strictly below every existing record,
    // guaranteeing it sorts first on the primary key. An explicit displayOrder in
    // the request (manual ordering) is still honoured.
    let displayOrder: number;
    if (typeof data.displayOrder === 'number') {
      displayOrder = data.displayOrder;
    } else {
      const lowest = await TemplateStyle.findOne({}).sort({ displayOrder: 1 }).select('displayOrder').lean();
      displayOrder = lowest && typeof lowest.displayOrder === 'number' ? lowest.displayOrder - 1 : 0;
    }

    const template = await TemplateStyle.create({
      ...pickEditable(data),
      name: data.name.trim(),
      slug,
      displayOrder,
      enabled: data.enabled !== undefined ? data.enabled : true,
      isDefault: false,
      createdById: (req as any).user?._id?.toString(),
    });
    res.status(201).json(template);
  } catch (error: any) {
    if (error.code === 11000) {
      res.status(409).json({ error: 'A template with this slug already exists' });
      return;
    }
    console.error('[SuperAdmin] Create template style error:', error.message);
    res.status(500).json({ error: 'Failed to create template style' });
  }
});

// --- Get single ---
router.get('/:id', async (req: Request, res: Response) => {
  try {
    const { TemplateStyle } = getModels();
    const template = await TemplateStyle.findById(req.params.id).lean();
    if (!template) {
      res.status(404).json({ error: 'Template style not found' });
      return;
    }
    res.json(template);
  } catch (error: any) {
    console.error('[SuperAdmin] Get template style error:', error.message);
    res.status(500).json({ error: 'Failed to fetch template style' });
  }
});

// --- Update ---
router.put('/:id', async (req: Request, res: Response) => {
  try {
    const { TemplateStyle } = getModels();
    const existing = await TemplateStyle.findById(req.params.id).lean();
    if (!existing) {
      res.status(404).json({ error: 'Template style not found' });
      return;
    }
    const validationError = validateFields(req.body);
    if (validationError) {
      res.status(400).json({ error: validationError });
      return;
    }
    const update = pickEditable(req.body);
    if (update.name !== undefined) update.name = String(update.name).trim();
    const updated = await TemplateStyle.findByIdAndUpdate(
      req.params.id,
      { $set: update },
      { new: true, runValidators: true }
    ).lean();
    res.json(updated);
  } catch (error: any) {
    console.error('[SuperAdmin] Update template style error:', error.message);
    res.status(500).json({ error: 'Failed to update template style' });
  }
});

// --- Toggle enable/disable ---
router.put('/:id/enabled', async (req: Request, res: Response) => {
  try {
    const { TemplateStyle } = getModels();
    const { enabled } = req.body;
    if (typeof enabled !== 'boolean') {
      res.status(400).json({ error: 'enabled must be a boolean' });
      return;
    }
    const updated = await TemplateStyle.findByIdAndUpdate(
      req.params.id,
      { $set: { enabled } },
      { new: true, runValidators: true }
    ).lean();
    if (!updated) {
      res.status(404).json({ error: 'Template style not found' });
      return;
    }
    res.json(updated);
  } catch (error: any) {
    console.error('[SuperAdmin] Toggle template style error:', error.message);
    res.status(500).json({ error: 'Failed to update template style' });
  }
});

// --- Delete ---
router.delete('/:id', async (req: Request, res: Response) => {
  try {
    const { TemplateStyle } = getModels();
    const template = await TemplateStyle.findById(req.params.id).lean();
    if (!template) {
      res.status(404).json({ error: 'Template style not found' });
      return;
    }
    await TemplateStyle.findByIdAndDelete(req.params.id);
    res.json({ message: 'Template style deleted', id: req.params.id });
  } catch (error: any) {
    console.error('[SuperAdmin] Delete template style error:', error.message);
    res.status(500).json({ error: 'Failed to delete template style' });
  }
});

export default router;
