// routes/archerTemplates.js
const express = require('express');
const pool = require('../db');
const { requireAuth, requireGroup } = require('../middleware/auth');
const logAudit = require('../helpers/auditLog');

// Section fields and their max length
const SECTION_FIELDS = [
  'environment_overview',
  'segmentation',
  'mitigating_controls',
  'additional_info',
  'charter_network_banner',
  'data_classification',
  'charter_network',
  'additional_access_list'
];
const SECTION_MAX_LENGTH = 10000;

function createArcherTemplatesRouter() {
  const router = express.Router();

  // All Archer template routes require authentication and Admin or Standard_User group (page-level access)
  router.use(requireAuth());
  router.use(requireGroup('Admin', 'Standard_User'));

  // --- Hierarchy endpoints (MUST be defined before /:id to avoid route conflicts) ---

  /**
   * GET /api/archer-templates/hierarchy/vendors
   *
   * Returns a sorted array of distinct vendor names across all templates.
   *
   * @returns {string[]} 200 - Array of vendor names sorted alphabetically
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.get('/hierarchy/vendors', requireAuth(), async (req, res) => {
    try {
      const { rows } = await pool.query(
        'SELECT DISTINCT vendor FROM archer_templates ORDER BY vendor ASC'
      );
      res.json(rows.map(r => r.vendor));
    } catch (err) {
      console.error('Error fetching template vendors:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  /**
   * GET /api/archer-templates/hierarchy/platforms
   *
   * Returns a sorted array of distinct platform names for a given vendor.
   *
   * @query {string} vendor - (required) The vendor to filter platforms by
   * @returns {string[]} 200 - Array of platform names sorted alphabetically
   * @returns {object} 400 - { error: 'vendor query parameter is required' }
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.get('/hierarchy/platforms', requireAuth(), async (req, res) => {
    const { vendor } = req.query;
    if (!vendor) {
      return res.status(400).json({ error: 'vendor query parameter is required' });
    }
    try {
      const { rows } = await pool.query(
        'SELECT DISTINCT platform FROM archer_templates WHERE LOWER(TRIM(vendor)) = LOWER(TRIM($1)) ORDER BY platform ASC',
        [vendor]
      );
      res.json(rows.map(r => r.platform));
    } catch (err) {
      console.error('Error fetching template platforms:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  /**
   * GET /api/archer-templates/hierarchy/models
   *
   * Returns a sorted array of distinct model names for a given vendor and platform.
   *
   * @query {string} vendor - (required) The vendor to filter by
   * @query {string} platform - (required) The platform to filter by
   * @returns {string[]} 200 - Array of model names sorted alphabetically
   * @returns {object} 400 - { error: 'Missing required query parameters: ...' }
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.get('/hierarchy/models', requireAuth(), async (req, res) => {
    const { vendor, platform } = req.query;
    const missing = [];
    if (!vendor) missing.push('vendor');
    if (!platform) missing.push('platform');
    if (missing.length > 0) {
      return res.status(400).json({ error: `Missing required query parameters: ${missing.join(', ')}` });
    }
    try {
      const { rows } = await pool.query(
        'SELECT DISTINCT model FROM archer_templates WHERE LOWER(TRIM(vendor)) = LOWER(TRIM($1)) AND LOWER(TRIM(platform)) = LOWER(TRIM($2)) ORDER BY model ASC',
        [vendor, platform]
      );
      res.json(rows.map(r => r.model));
    } catch (err) {
      console.error('Error fetching template models:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  // --- Core CRUD endpoints ---

  /**
   * POST /api/archer-templates
   *
   * Creates a new Archer template with vendor/platform/model hierarchy and section content.
   * Requires Admin or Standard_User group.
   *
   * @body {string} vendor - (required) Vendor name, 1-100 chars after trim
   * @body {string} platform - (required) Platform name, 1-100 chars after trim
   * @body {string} model - (required) Model name, 1-100 chars after trim
   * @body {string} [environment_overview] - Section content, max 10,000 chars
   * @body {string} [segmentation] - Section content, max 10,000 chars
   * @body {string} [mitigating_controls] - Section content, max 10,000 chars
   * @body {string} [additional_info] - Section content, max 10,000 chars
   * @body {string} [charter_network_banner] - Section content, max 10,000 chars
   * @body {string} [data_classification] - Section content, max 10,000 chars
   * @body {string} [charter_network] - Section content, max 10,000 chars
   * @body {string} [additional_access_list] - Section content, max 10,000 chars
   * @returns {object} 201 - The created template record (all columns)
   * @returns {object} 400 - { error: 'validation message' }
   * @returns {object} 409 - { error: 'A template with this vendor/platform/model combination already exists' }
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.post('/', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
    const { vendor, platform, model } = req.body;

    // Validate vendor, platform, model — required, 1-100 chars after trim, non-empty after trim
    const errors = [];
    for (const [field, value] of [['vendor', vendor], ['platform', platform], ['model', model]]) {
      if (value === undefined || value === null || typeof value !== 'string' || value.trim().length === 0) {
        errors.push(`${field} is required`);
      } else if (value.trim().length > 100) {
        errors.push(`${field} must be 100 characters or fewer`);
      }
    }
    if (errors.length > 0) {
      return res.status(400).json({ error: errors.join('; ') });
    }

    // Validate section fields — max 10,000 chars each, default to empty string
    const sectionValues = {};
    for (const field of SECTION_FIELDS) {
      const val = req.body[field];
      if (val !== undefined && val !== null && typeof val === 'string') {
        if (val.length > SECTION_MAX_LENGTH) {
          return res.status(400).json({ error: `${field} must be 10,000 characters or fewer` });
        }
        sectionValues[field] = val;
      } else {
        sectionValues[field] = '';
      }
    }

    try {
      const { rows } = await pool.query(
        `INSERT INTO archer_templates (vendor, platform, model, environment_overview, segmentation, mitigating_controls, additional_info, charter_network_banner, data_classification, charter_network, additional_access_list, created_by)
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
         RETURNING *`,
        [
          vendor.trim(),
          platform.trim(),
          model.trim(),
          sectionValues.environment_overview,
          sectionValues.segmentation,
          sectionValues.mitigating_controls,
          sectionValues.additional_info,
          sectionValues.charter_network_banner,
          sectionValues.data_classification,
          sectionValues.charter_network,
          sectionValues.additional_access_list,
          req.user.id
        ]
      );

      // Fire-and-forget audit log
      logAudit({
        userId: req.user.id,
        username: req.user.username,
        action: 'template_created',
        entityType: 'archer_template',
        entityId: String(rows[0].id),
        details: { vendor: vendor.trim(), platform: platform.trim(), model: model.trim() },
        ipAddress: req.ip
      });

      res.status(201).json(rows[0]);
    } catch (err) {
      if (err.code === '23505') {
        return res.status(409).json({ error: 'A template with this vendor/platform/model combination already exists' });
      }
      console.error('Error creating template:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  /**
   * GET /api/archer-templates
   *
   * Lists all templates with optional search and exact-match filters.
   * Results are sorted by vendor, platform, model (ascending).
   *
   * @query {string} [search] - Substring search across vendor, platform, and model (ILIKE)
   * @query {string} [vendor] - Exact-match filter on vendor (case-insensitive)
   * @query {string} [platform] - Exact-match filter on platform (case-insensitive)
   * @query {string} [model] - Exact-match filter on model (case-insensitive)
   * @returns {object[]} 200 - Array of template records sorted by vendor/platform/model
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.get('/', requireAuth(), async (req, res) => {
    const { search, vendor, platform, model } = req.query;

    let query = 'SELECT * FROM archer_templates WHERE 1=1';
    const params = [];
    let paramIndex = 1;

    // Search — ILIKE substring match across vendor, platform, model
    const trimmedSearch = search ? search.trim() : '';
    if (trimmedSearch.length > 0) {
      query += ` AND (vendor ILIKE $${paramIndex} OR platform ILIKE $${paramIndex} OR model ILIKE $${paramIndex})`;
      params.push(`%${trimmedSearch}%`);
      paramIndex++;
    }

    // Exact-match filters (case-insensitive via LOWER/TRIM)
    if (vendor) {
      query += ` AND LOWER(TRIM(vendor)) = LOWER(TRIM($${paramIndex}))`;
      params.push(vendor);
      paramIndex++;
    }
    if (platform) {
      query += ` AND LOWER(TRIM(platform)) = LOWER(TRIM($${paramIndex}))`;
      params.push(platform);
      paramIndex++;
    }
    if (model) {
      query += ` AND LOWER(TRIM(model)) = LOWER(TRIM($${paramIndex}))`;
      params.push(model);
      paramIndex++;
    }

    query += ' ORDER BY vendor ASC, platform ASC, model ASC';

    try {
      const { rows } = await pool.query(query, params);
      res.json(rows);
    } catch (err) {
      console.error('Error fetching templates:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  /**
   * POST /api/archer-templates/:id/clone
   *
   * Clones an existing template's section content into a new template with different
   * vendor/platform/model hierarchy values. Requires Admin or Standard_User group.
   *
   * @param {number} id - The ID of the source template to clone from
   * @body {string} vendor - (required) New vendor name, 1-100 chars after trim
   * @body {string} platform - (required) New platform name, 1-100 chars after trim
   * @body {string} model - (required) New model name, 1-100 chars after trim
   * @returns {object} 201 - The newly created cloned template record
   * @returns {object} 400 - { error: 'validation message' }
   * @returns {object} 404 - { error: 'Template not found' }
   * @returns {object} 409 - { error: 'A template with this vendor/platform/model combination already exists' }
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.post('/:id/clone', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
    const { id } = req.params;
    const { vendor, platform, model } = req.body;

    // Validate vendor, platform, model — required, 1-100 chars after trim, non-empty after trim
    const errors = [];
    for (const [field, value] of [['vendor', vendor], ['platform', platform], ['model', model]]) {
      if (value === undefined || value === null || typeof value !== 'string' || value.trim().length === 0) {
        errors.push(`${field} is required`);
      } else if (value.trim().length > 100) {
        errors.push(`${field} must be 100 characters or fewer`);
      }
    }
    if (errors.length > 0) {
      return res.status(400).json({ error: errors.join('; ') });
    }

    try {
      // Verify source template exists
      const { rows: sourceRows } = await pool.query('SELECT * FROM archer_templates WHERE id = $1', [id]);
      if (sourceRows.length === 0) {
        return res.status(404).json({ error: 'Template not found' });
      }
      const source = sourceRows[0];

      // INSERT copying all 8 section fields from source with new hierarchy values
      const { rows } = await pool.query(
        `INSERT INTO archer_templates (vendor, platform, model, environment_overview, segmentation, mitigating_controls, additional_info, charter_network_banner, data_classification, charter_network, additional_access_list, created_by)
         VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
         RETURNING *`,
        [
          vendor.trim(),
          platform.trim(),
          model.trim(),
          source.environment_overview,
          source.segmentation,
          source.mitigating_controls,
          source.additional_info,
          source.charter_network_banner,
          source.data_classification,
          source.charter_network,
          source.additional_access_list,
          req.user.id
        ]
      );

      // Fire-and-forget audit log
      logAudit({
        userId: req.user.id,
        username: req.user.username,
        action: 'template_cloned',
        entityType: 'archer_template',
        entityId: String(rows[0].id),
        details: { sourceId: Number(id), newId: rows[0].id, vendor: vendor.trim(), platform: platform.trim(), model: model.trim() },
        ipAddress: req.ip
      });

      res.status(201).json(rows[0]);
    } catch (err) {
      if (err.code === '23505') {
        return res.status(409).json({ error: 'A template with this vendor/platform/model combination already exists' });
      }
      console.error('Error cloning template:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  /**
   * GET /api/archer-templates/:id
   *
   * Fetches a single template by its ID.
   *
   * @param {number} id - The template ID
   * @returns {object} 200 - The template record
   * @returns {object} 404 - { error: 'Template not found' }
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.get('/:id', requireAuth(), async (req, res) => {
    const { id } = req.params;
    try {
      const { rows } = await pool.query('SELECT * FROM archer_templates WHERE id = $1', [id]);
      if (rows.length === 0) {
        return res.status(404).json({ error: 'Template not found' });
      }
      res.json(rows[0]);
    } catch (err) {
      console.error('Error fetching template:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  /**
   * PUT /api/archer-templates/:id
   *
   * Updates an existing template. Supports partial updates — only provided fields are changed.
   * Always updates `updated_at` to NOW(). Requires Admin or Standard_User group.
   *
   * @param {number} id - The template ID to update
   * @body {string} [vendor] - New vendor name, 1-100 chars after trim
   * @body {string} [platform] - New platform name, 1-100 chars after trim
   * @body {string} [model] - New model name, 1-100 chars after trim
   * @body {string} [environment_overview] - Section content, max 10,000 chars
   * @body {string} [segmentation] - Section content, max 10,000 chars
   * @body {string} [mitigating_controls] - Section content, max 10,000 chars
   * @body {string} [additional_info] - Section content, max 10,000 chars
   * @body {string} [charter_network_banner] - Section content, max 10,000 chars
   * @body {string} [data_classification] - Section content, max 10,000 chars
   * @body {string} [charter_network] - Section content, max 10,000 chars
   * @body {string} [additional_access_list] - Section content, max 10,000 chars
   * @returns {object} 200 - The updated template record
   * @returns {object} 400 - { error: 'validation message' }
   * @returns {object} 404 - { error: 'Template not found' }
   * @returns {object} 409 - { error: 'A template with this vendor/platform/model combination already exists' }
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.put('/:id', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
    const { id } = req.params;

    try {
      // Verify template exists
      const { rows: existingRows } = await pool.query('SELECT * FROM archer_templates WHERE id = $1', [id]);
      if (existingRows.length === 0) {
        return res.status(404).json({ error: 'Template not found' });
      }
      const existing = existingRows[0];

      // Validate provided hierarchy fields
      const errors = [];
      const updatedFields = {};
      const changedFieldNames = [];

      for (const field of ['vendor', 'platform', 'model']) {
        const value = req.body[field];
        if (value !== undefined) {
          if (value === null || typeof value !== 'string' || value.trim().length === 0) {
            errors.push(`${field} is required`);
          } else if (value.trim().length > 100) {
            errors.push(`${field} must be 100 characters or fewer`);
          } else {
            updatedFields[field] = value.trim();
            if (value.trim() !== existing[field]) {
              changedFieldNames.push(field);
            }
          }
        }
      }

      // Validate provided section fields
      for (const field of SECTION_FIELDS) {
        const val = req.body[field];
        if (val !== undefined) {
          if (val !== null && typeof val === 'string') {
            if (val.length > SECTION_MAX_LENGTH) {
              errors.push(`${field} must be 10,000 characters or fewer`);
            } else {
              updatedFields[field] = val;
              if (val !== existing[field]) {
                changedFieldNames.push(field);
              }
            }
          } else {
            updatedFields[field] = '';
            if ('' !== existing[field]) {
              changedFieldNames.push(field);
            }
          }
        }
      }

      if (errors.length > 0) {
        return res.status(400).json({ error: errors.join('; ') });
      }

      // Check uniqueness if vendor/platform/model changed (excluding self)
      const newVendor = updatedFields.vendor || existing.vendor;
      const newPlatform = updatedFields.platform || existing.platform;
      const newModel = updatedFields.model || existing.model;

      if (updatedFields.vendor !== undefined || updatedFields.platform !== undefined || updatedFields.model !== undefined) {
        const { rows: conflictRows } = await pool.query(
          `SELECT id FROM archer_templates WHERE LOWER(TRIM(vendor)) = LOWER(TRIM($1)) AND LOWER(TRIM(platform)) = LOWER(TRIM($2)) AND LOWER(TRIM(model)) = LOWER(TRIM($3)) AND id != $4`,
          [newVendor, newPlatform, newModel, id]
        );
        if (conflictRows.length > 0) {
          return res.status(409).json({ error: 'A template with this vendor/platform/model combination already exists' });
        }
      }

      // Build dynamic UPDATE SET clause for only provided fields
      const setClauses = [];
      const params = [];
      let paramIndex = 1;

      for (const [field, value] of Object.entries(updatedFields)) {
        setClauses.push(`${field} = $${paramIndex}`);
        params.push(value);
        paramIndex++;
      }

      // Always set updated_at = NOW()
      setClauses.push(`updated_at = NOW()`);

      // Execute update
      params.push(id);
      const { rows } = await pool.query(
        `UPDATE archer_templates SET ${setClauses.join(', ')} WHERE id = $${paramIndex} RETURNING *`,
        params
      );

      // Fire-and-forget audit log
      logAudit({
        userId: req.user.id,
        username: req.user.username,
        action: 'template_updated',
        entityType: 'archer_template',
        entityId: String(id),
        details: { changedFields: changedFieldNames },
        ipAddress: req.ip
      });

      res.json(rows[0]);
    } catch (err) {
      console.error('Error updating template:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  /**
   * DELETE /api/archer-templates/:id
   *
   * Permanently deletes a template. Requires Admin or Standard_User group.
   *
   * @param {number} id - The template ID to delete
   * @returns {object} 200 - { message: 'Template deleted successfully' }
   * @returns {object} 404 - { error: 'Template not found' }
   * @returns {object} 500 - { error: 'Internal server error' }
   */
  router.delete('/:id', requireAuth(), requireGroup('Admin', 'Standard_User'), async (req, res) => {
    const { id } = req.params;

    try {
      // Verify template exists
      const { rows: existingRows } = await pool.query('SELECT * FROM archer_templates WHERE id = $1', [id]);
      if (existingRows.length === 0) {
        return res.status(404).json({ error: 'Template not found' });
      }
      const existing = existingRows[0];

      // Delete the template
      await pool.query('DELETE FROM archer_templates WHERE id = $1', [id]);

      // Fire-and-forget audit log
      logAudit({
        userId: req.user.id,
        username: req.user.username,
        action: 'template_deleted',
        entityType: 'archer_template',
        entityId: String(id),
        details: { vendor: existing.vendor, platform: existing.platform, model: existing.model },
        ipAddress: req.ip
      });

      res.json({ message: 'Template deleted successfully' });
    } catch (err) {
      console.error('Error deleting template:', err);
      res.status(500).json({ error: 'Internal server error' });
    }
  });

  return router;
}

module.exports = createArcherTemplatesRouter;
