/**
 * Issue Tracker — Trinity Console
 *
 * Task #166 — REQ-2026-04-14-issue-tracker (Chronicler #89)
 * Holly's primary submission channel. Mobile-first form, screenshot upload
 * from camera roll, minimal fields, fire-and-forget.
 *
 * Session auth (shared admin middleware). REST-at-distance via /api/internal/issues
 * lives in src/routes/api.js for n8n/external submission.
 *
 * Routes
 *   GET  /admin/issues                 — list + filters
 *   GET  /admin/issues/new             — mobile submit form
 *   POST /admin/issues                 — create (with optional screenshots)
 *   GET  /admin/issues/:id             — detail page
 *   POST /admin/issues/:id/status      — change status (HTMX)
 *   POST /admin/issues/:id/assign      — change assignee (HTMX)
 *   POST /admin/issues/:id/comments    — add comment
 *   POST /admin/issues/:id/upload      — add more screenshots after create
 */

const express = require('express');
const path = require('path');
const fs = require('fs');
const multer = require('multer');
const db = require('../../database');
const notifier = require('../../services/issueNotifier');

const router = express.Router();

const STATUSES   = ['open', 'in_progress', 'blocked', 'resolved', 'closed'];
const PRIORITIES = ['critical', 'high', 'medium', 'low'];
const CATEGORIES = ['bug', 'feature', 'content', 'infrastructure', 'holly', 'general'];
const ASSIGNEES  = ['Michael', 'Meg', 'Holly', 'Trinity', 'unassigned'];

// -----------------------------------------------------------------------------
// Upload storage
// -----------------------------------------------------------------------------
const UPLOAD_DIR = path.resolve(__dirname, '..', '..', '..', 'uploads', 'issues');
fs.mkdirSync(UPLOAD_DIR, { recursive: true });

const storage = multer.diskStorage({
  destination: (req, file, cb) => cb(null, UPLOAD_DIR),
  filename: (req, file, cb) => {
    const ext = path.extname(file.originalname).toLowerCase().slice(0, 8);
    const unique = Date.now() + '-' + Math.random().toString(36).slice(2, 10);
    cb(null, `${unique}${ext}`);
  }
});

const upload = multer({
  storage,
  limits: { fileSize: 10 * 1024 * 1024, files: 6 }, // 10MB each, max 6 screenshots
  fileFilter: (req, file, cb) => {
    if (!/^image\//.test(file.mimetype)) {
      return cb(new Error('Only image uploads are allowed'));
    }
    cb(null, true);
  }
});

// Lenient wrapper so multer errors don't kill the request
function uploadMaybe(field) {
  return (req, res, next) => {
    upload.array(field, 6)(req, res, (err) => {
      if (err) {
        console.warn('[Issues] upload warning:', err.message);
        req.uploadError = err.message;
      }
      next();
    });
  };
}

// -----------------------------------------------------------------------------
// Helpers
// -----------------------------------------------------------------------------
async function nextIssueNumber() {
  const r = await db.query('SELECT COALESCE(MAX(issue_number), 0) + 1 AS n FROM issues');
  return r.rows[0].n;
}

async function loadIssueFull(id) {
  const iss = await db.query('SELECT * FROM issues WHERE id = $1', [id]);
  if (iss.rows.length === 0) return null;
  const issue = iss.rows[0];
  const atts = await db.query(
    'SELECT * FROM issue_attachments WHERE issue_id = $1 ORDER BY uploaded_at ASC',
    [id]
  );
  const cmts = await db.query(
    'SELECT * FROM issue_comments WHERE issue_id = $1 ORDER BY created_at ASC',
    [id]
  );
  issue.attachments = atts.rows;
  issue.comments = cmts.rows;
  return issue;
}

function currentUsername(req) {
  return req.user?.username || req.user?.global_name || 'Trinity Console';
}

// -----------------------------------------------------------------------------
// GET /admin/issues — list
// -----------------------------------------------------------------------------
router.get('/', async (req, res) => {
  try {
    const { status, priority, category, submitter, sort } = req.query;
    const params = [];
    let where = 'WHERE 1=1';
    let p = 0;

    if (status)    { p++; where += ` AND status    = $${p}`; params.push(status); }
    else if (!req.query.all) { where += ` AND status NOT IN ('resolved','closed')`; }
    if (priority)  { p++; where += ` AND priority  = $${p}`; params.push(priority); }
    if (category)  { p++; where += ` AND category  = $${p}`; params.push(category); }
    if (submitter) { p++; where += ` AND submitted_by = $${p}`; params.push(submitter); }

    let order = `CASE status
                   WHEN 'in_progress' THEN 1 WHEN 'blocked' THEN 2 WHEN 'open' THEN 3
                   WHEN 'resolved' THEN 4 WHEN 'closed' THEN 5 END,
                 CASE priority
                   WHEN 'critical' THEN 1 WHEN 'high' THEN 2
                   WHEN 'medium' THEN 3 WHEN 'low' THEN 4 END,
                 issue_number DESC`;
    if (sort === 'newest')   order = 'created_at DESC';
    if (sort === 'updated')  order = 'updated_at DESC';
    if (sort === 'priority') order = `CASE priority WHEN 'critical' THEN 1 WHEN 'high' THEN 2 WHEN 'medium' THEN 3 WHEN 'low' THEN 4 END, issue_number DESC`;

    const result = await db.query(
      `SELECT i.*,
              (SELECT COUNT(*) FROM issue_attachments a WHERE a.issue_id = i.id) AS attachment_count,
              (SELECT COUNT(*) FROM issue_comments c WHERE c.issue_id = i.id) AS comment_count
       FROM issues i ${where}
       ORDER BY ${order}`,
      params
    );

    const stats = await db.query(`
      SELECT
        COUNT(*) FILTER (WHERE status NOT IN ('resolved','closed')) AS active,
        COUNT(*) FILTER (WHERE status = 'open')        AS open,
        COUNT(*) FILTER (WHERE status = 'in_progress') AS in_progress,
        COUNT(*) FILTER (WHERE status = 'blocked')     AS blocked,
        COUNT(*) FILTER (WHERE priority IN ('critical','high') AND status NOT IN ('resolved','closed')) AS urgent
      FROM issues
    `);

    res.render('admin/issues/index', {
      title: 'Issues',
      currentPath: '/issues',
      issues: result.rows,
      stats: stats.rows[0],
      filters: { status, priority, category, submitter, sort, all: req.query.all },
      statuses: STATUSES,
      priorities: PRIORITIES,
      categories: CATEGORIES,
      assignees: ASSIGNEES,
      adminUser: req.user,
      layout: 'layout'
    });
  } catch (err) {
    console.error('[Issues] list error:', err);
    res.status(500).send('Error loading issues');
  }
});

// -----------------------------------------------------------------------------
// GET /admin/issues/new — mobile-first submit form
// -----------------------------------------------------------------------------
router.get('/new', (req, res) => {
  res.render('admin/issues/new', {
    title: 'New Issue',
    currentPath: '/issues',
    priorities: PRIORITIES,
    categories: CATEGORIES,
    adminUser: req.user,
    layout: 'layout'
  });
});

// -----------------------------------------------------------------------------
// POST /admin/issues — create
// -----------------------------------------------------------------------------
router.post('/', uploadMaybe('screenshots'), async (req, res) => {
  try {
    const { title, description, priority, category } = req.body;
    if (!title || !title.trim()) {
      return res.status(400).send('Title required');
    }

    const issueNumber = await nextIssueNumber();
    const submittedBy = currentUsername(req);

    const inserted = await db.query(
      `INSERT INTO issues (issue_number, title, description, priority, category, submitted_by)
       VALUES ($1, $2, $3, $4, $5, $6) RETURNING *`,
      [
        issueNumber,
        title.trim(),
        description || null,
        PRIORITIES.includes(priority) ? priority : 'medium',
        CATEGORIES.includes(category) ? category : 'general',
        submittedBy
      ]
    );
    const issue = inserted.rows[0];

    // Attach screenshots
    if (req.files && req.files.length > 0) {
      for (const f of req.files) {
        await db.query(
          `INSERT INTO issue_attachments (issue_id, filename, original_name, mime_type, file_size)
           VALUES ($1, $2, $3, $4, $5)`,
          [issue.id, f.filename, f.originalname, f.mimetype, f.size]
        );
      }
    }

    console.log(`🐛 [Issues] #${issueNumber} opened by ${submittedBy}: ${title}`);
    notifier.notifyCreated(issue);

    res.redirect(`/admin/issues/${issue.id}`);
  } catch (err) {
    console.error('[Issues] create error:', err);
    res.status(500).send('Error creating issue');
  }
});

// -----------------------------------------------------------------------------
// GET /admin/issues/:id — detail
// -----------------------------------------------------------------------------
router.get('/:id(\\d+)', async (req, res) => {
  try {
    const issue = await loadIssueFull(req.params.id);
    if (!issue) return res.status(404).send('Issue not found');

    res.render('admin/issues/detail', {
      title: `Issue #${issue.issue_number}`,
      currentPath: '/issues',
      issue,
      statuses: STATUSES,
      priorities: PRIORITIES,
      categories: CATEGORIES,
      assignees: ASSIGNEES,
      adminUser: req.user,
      layout: 'layout'
    });
  } catch (err) {
    console.error('[Issues] detail error:', err);
    res.status(500).send('Error loading issue');
  }
});

// -----------------------------------------------------------------------------
// POST /admin/issues/:id/status
// -----------------------------------------------------------------------------
router.post('/:id(\\d+)/status', async (req, res) => {
  try {
    const { status } = req.body;
    if (!STATUSES.includes(status)) return res.status(400).send('Invalid status');

    const actor = currentUsername(req);
    const extras = [];
    const params = [status, req.params.id];

    if (status === 'resolved' || status === 'closed') {
      extras.push('resolved_at = NOW()', `resolved_by = $3`);
      params.splice(2, 0, actor);
    }

    const sql = `UPDATE issues SET status = $1, updated_at = NOW()${extras.length ? ', ' + extras.join(', ') : ''}
                 WHERE id = $${params.length} RETURNING *`;
    const r = await db.query(sql, params);
    if (r.rows.length === 0) return res.status(404).send('Not found');

    notifier.notifyStatusChange(r.rows[0], status, actor);
    res.redirect(`/admin/issues/${req.params.id}`);
  } catch (err) {
    console.error('[Issues] status error:', err);
    res.status(500).send('Error updating status');
  }
});

// -----------------------------------------------------------------------------
// POST /admin/issues/:id/assign
// -----------------------------------------------------------------------------
router.post('/:id(\\d+)/assign', async (req, res) => {
  try {
    const { assigned_to } = req.body;
    await db.query(
      `UPDATE issues SET assigned_to = $1, updated_at = NOW() WHERE id = $2`,
      [assigned_to || 'unassigned', req.params.id]
    );
    res.redirect(`/admin/issues/${req.params.id}`);
  } catch (err) {
    console.error('[Issues] assign error:', err);
    res.status(500).send('Error updating assignment');
  }
});

// -----------------------------------------------------------------------------
// POST /admin/issues/:id/comments
// -----------------------------------------------------------------------------
router.post('/:id(\\d+)/comments', async (req, res) => {
  try {
    const { content } = req.body;
    if (!content || !content.trim()) return res.redirect(`/admin/issues/${req.params.id}`);

    const author = currentUsername(req);
    await db.query(
      `INSERT INTO issue_comments (issue_id, author, content) VALUES ($1, $2, $3)`,
      [req.params.id, author, content.trim()]
    );
    await db.query(`UPDATE issues SET updated_at = NOW() WHERE id = $1`, [req.params.id]);

    const issue = await loadIssueFull(req.params.id);
    if (issue) notifier.notifyComment(issue, author);

    res.redirect(`/admin/issues/${req.params.id}`);
  } catch (err) {
    console.error('[Issues] comment error:', err);
    res.status(500).send('Error adding comment');
  }
});

// -----------------------------------------------------------------------------
// POST /admin/issues/:id/upload — add screenshots post-hoc
// -----------------------------------------------------------------------------
router.post('/:id(\\d+)/upload', uploadMaybe('screenshots'), async (req, res) => {
  try {
    if (req.files && req.files.length > 0) {
      for (const f of req.files) {
        await db.query(
          `INSERT INTO issue_attachments (issue_id, filename, original_name, mime_type, file_size)
           VALUES ($1, $2, $3, $4, $5)`,
          [req.params.id, f.filename, f.originalname, f.mimetype, f.size]
        );
      }
      await db.query(`UPDATE issues SET updated_at = NOW() WHERE id = $1`, [req.params.id]);
    }
    res.redirect(`/admin/issues/${req.params.id}`);
  } catch (err) {
    console.error('[Issues] upload error:', err);
    res.status(500).send('Error uploading attachments');
  }
});

// -----------------------------------------------------------------------------
// GET /admin/issues/attachments/:filename — serve image
// -----------------------------------------------------------------------------
router.get('/attachments/:filename', (req, res) => {
  const name = req.params.filename;
  if (!/^[a-zA-Z0-9._-]+$/.test(name)) return res.status(400).send('Bad filename');
  const abs = path.join(UPLOAD_DIR, name);
  if (!abs.startsWith(UPLOAD_DIR) || !fs.existsSync(abs)) return res.status(404).send('Not found');
  res.sendFile(abs);
});

module.exports = router;
