// ============================================================
// ENCOUNTERS ROUTES — Save/resume/pause encounter progress
// ============================================================

var express = require('express');
var router = express.Router();
var db = require('../db/database');
var { authMiddleware } = require('../middleware/auth');
var logger = require('../utils/logger');
var cryptoUtil = require('../utils/crypto');

router.use(authMiddleware);

// Normalise partial_data to a string before encrypting so JSON objects and
// raw strings round-trip identically. Decryption returns the original string.
function partialToString(partial_data) {
  if (partial_data == null) return '{}';
  if (typeof partial_data === 'object') return JSON.stringify(partial_data);
  return partial_data;
}

// ── GET all saved encounters for current user ────────────────────────────
router.get('/encounters/saved', async function(req, res) {
  try {
    // transcript/generated_note are encrypted at rest, so we can't slice on
    // the server with LEFT(..,200). Fetch full columns, decrypt in Node, then
    // preview. With a 7-day auto-delete the row count is small; the cost is
    // a handful of AES-GCM decrypts per list call.
    var rows = await db.all(
      "SELECT id, label, enc_type, status, created_at, updated_at, expires_at, transcript, generated_note FROM saved_encounters WHERE user_id = $1 AND expires_at > NOW() ORDER BY updated_at DESC",
      [req.user.id]
    );
    var out = rows.map(function (r) {
      var t = '', n = '';
      try { t = cryptoUtil.decryptString(r.transcript) || ''; } catch (e) {}
      try { n = cryptoUtil.decryptString(r.generated_note) || ''; } catch (e) {}
      return {
        id: r.id,
        label: r.label,
        enc_type: r.enc_type,
        status: r.status,
        created_at: r.created_at,
        updated_at: r.updated_at,
        expires_at: r.expires_at,
        transcript_preview: t.substring(0, 200),
        note_preview: n.substring(0, 200)
      };
    });
    res.json({ success: true, encounters: out });
  } catch (e) { logger.error('GET /encounters/saved', e.message); res.status(500).json({ error: 'Request failed' }); }
});

// ── GET single saved encounter ───────────────────────────────────────────
router.get('/encounters/saved/:id', async function(req, res) {
  try {
    var row = await db.get(
      'SELECT * FROM saved_encounters WHERE id = $1 AND user_id = $2 AND expires_at > NOW()',
      [req.params.id, req.user.id]
    );
    if (!row) return res.status(404).json({ error: 'Encounter not found or expired' });
    try { row.transcript      = cryptoUtil.decryptString(row.transcript); }      catch (e) {}
    try { row.generated_note  = cryptoUtil.decryptString(row.generated_note); }  catch (e) {}
    try { row.partial_data    = cryptoUtil.decryptString(row.partial_data); }    catch (e) {}
    logger.audit(req.user.id, 'encounter_load', 'Loaded encounter id:' + req.params.id, req, { category: 'clinical' });
    res.json({ success: true, encounter: row });
  } catch (e) { logger.error('GET /encounters/saved/:id', e.message); res.status(500).json({ error: 'Request failed' }); }
});

// ── POST save/update encounter progress ─────────────────────────────────
router.post('/encounters/saved', async function(req, res) {
  try {
    var { id, label, enc_type, transcript, generated_note, partial_data, status, idempotency_key } = req.body;
    var autoDeleteDays = parseInt(await db.getSetting('site.auto_delete_days') || '7', 10);

    if (id) {
      // Update existing — optimistic locking via `version` column.
      // Client passes req.body.expected_version (from the last GET). If
      // it doesn't match, another tab/user wrote first and we reject
      // with 409. If client doesn't send a version, we fall back to the
      // old behaviour (last-write-wins) for backwards compat.
      var existing = await db.get('SELECT id, version FROM saved_encounters WHERE id = $1 AND user_id = $2', [id, req.user.id]);
      if (!existing) return res.status(404).json({ error: 'Not found' });
      var expected = req.body.expected_version;
      if (expected != null && Number(expected) !== Number(existing.version || 1)) {
        return res.status(409).json({ error: 'Encounter was modified in another tab or session. Reload to see the latest.', currentVersion: existing.version, yourVersion: expected });
      }
      var newVersion = (Number(existing.version) || 1) + 1;
      var upd = await db.run(
        'UPDATE saved_encounters SET label=$1, transcript=$2, generated_note=$3, partial_data=$4, status=$5, version=$6, updated_at=NOW() WHERE id=$7 AND user_id=$8 AND (version = $9 OR $9::int IS NULL)',
        [
          label || 'Untitled',
          cryptoUtil.encryptString(transcript || ''),
          cryptoUtil.encryptString(generated_note || ''),
          cryptoUtil.encryptString(partialToString(partial_data)),
          status || 'active',
          newVersion,
          id, req.user.id,
          expected != null ? Number(expected) : null
        ]
      );
      if (upd.changes === 0) {
        // Someone else wrote between our SELECT and UPDATE
        return res.status(409).json({ error: 'Encounter changed under you. Reload and retry.' });
      }
      res.json({ success: true, id: id, version: newVersion });
      logger.audit(req.user.id, 'encounter_save', 'Saved encounter id:' + id, req, { category: 'clinical' });
    } else {
      // Enforce unique label per user (within active/non-expired encounters)
      if (label && label.trim()) {
        var labelDup = await db.get(
          "SELECT id FROM saved_encounters WHERE user_id = $1 AND LOWER(label) = LOWER($2) AND expires_at > NOW()",
          [req.user.id, label.trim()]
        );
        if (labelDup) {
          return res.status(409).json({ error: 'An encounter with this label already exists. Use a unique label or load the existing one.' });
        }
      }
      // Check for duplicate via idempotency_key
      if (idempotency_key) {
        var dup = await db.get(
          'SELECT id FROM saved_encounters WHERE user_id = $1 AND idempotency_key = $2',
          [req.user.id, idempotency_key]
        );
        if (dup) {
          // Update existing instead of creating duplicate
          await db.run(
            'UPDATE saved_encounters SET label=$1, transcript=$2, generated_note=$3, partial_data=$4, status=$5, updated_at=NOW() WHERE id=$6 AND user_id=$7',
            [
              label || 'Untitled',
              cryptoUtil.encryptString(transcript || ''),
              cryptoUtil.encryptString(generated_note || ''),
              cryptoUtil.encryptString(partialToString(partial_data)),
              status || 'active',
              dup.id, req.user.id
            ]
          );
          logger.audit(req.user.id, 'encounter_save', 'Saved encounter id:' + dup.id, req, { category: 'clinical' });
          return res.json({ success: true, id: dup.id });
        }
      }
      // Create new
      var result = await db.run(
        'INSERT INTO saved_encounters (user_id, label, enc_type, transcript, generated_note, partial_data, status, idempotency_key, expires_at) VALUES ($1,$2,$3,$4,$5,$6,$7,$8, NOW() + ($9 || \' days\')::INTERVAL)',
        [
          req.user.id,
          label || 'Untitled',
          enc_type || 'encounter',
          cryptoUtil.encryptString(transcript || ''),
          cryptoUtil.encryptString(generated_note || ''),
          cryptoUtil.encryptString(partialToString(partial_data)),
          status || 'active',
          idempotency_key || null,
          autoDeleteDays
        ]
      );
      res.json({ success: true, id: result.lastInsertRowid });
      logger.audit(req.user.id, 'encounter_save', 'Saved encounter id:' + result.lastInsertRowid, req, { category: 'clinical' });
    }
  } catch (e) { logger.error('POST /encounters/saved', e.message); res.status(500).json({ error: 'Request failed' }); }
});

// ── DELETE saved encounter ───────────────────────────────────────────────
router.delete('/encounters/saved/:id', async function(req, res) {
  try {
    var result = await db.run(
      'DELETE FROM saved_encounters WHERE id = $1 AND user_id = $2',
      [req.params.id, req.user.id]
    );
    if (result.changes === 0) return res.status(404).json({ error: 'Not found' });
    res.json({ success: true });
    logger.audit(req.user.id, 'encounter_delete', 'Deleted encounter ' + req.params.id, req, { category: 'clinical' });
  } catch (e) { logger.error('DELETE /encounters/saved/:id', e.message); res.status(500).json({ error: 'Request failed' }); }
});

module.exports = router;
