// ============================================================
// ED ENCOUNTER ROUTE — multi-stage emergency department note
// generation with don't-miss tooltips and 2023 E/M MDM finalize.
//
// Two endpoints, both auth-gated:
//   POST /api/ed-encounters/generate  — per-stage note + tooltips
//   POST /api/ed-encounters/finalize  — MDM block for billing
//
// Stage state lives client-side (localStorage + draft row in
// saved_encounters via the existing encounters route). This file
// is purely AI plumbing — it does not own persistence.
// ============================================================

var express = require('express');
var router  = express.Router();
var { callAI }          = require('../utils/ai');
var PROMPTS             = require('../utils/prompts');
var { authMiddleware }  = require('../middleware/auth');
var logger              = require('../utils/logger');
var { wrapUserText, INJECTION_GUARD } = require('../utils/promptSafe');

router.use(authMiddleware);

// Models sometimes wrap JSON in ```json fences or prepend prose. Strip the
// fence and recover the JSON object between the first { and last }.
function extractJson(raw) {
  var t = String(raw || '').trim();
  t = t.replace(/^```(?:json)?\s*/i, '').replace(/\s*```$/i, '');
  var s = t.indexOf('{');
  if (s > 0) t = t.substring(s);
  var e = t.lastIndexOf('}');
  if (e > -1 && e < t.length - 1) t = t.substring(0, e + 1);
  try { return JSON.parse(t); } catch (err) { return null; }
}

// ── POST /ed-encounters/generate — one stage of an ED encounter ─────
// Body:
//   stage              (1, 2, ...)  — informational, drives "previous note" handling
//   transcript         — current stage's voice transcript (required)
//   chiefComplaint     — string, required
//   patientAge         — string, optional but strongly preferred
//   patientGender      — string, optional
//   previousNote       — string, only on stage > 1, the last generated note
//   physicianMemories  — string from /api/memories/context, optional
//   model              — admin/user-selected model id, optional
// Returns: { success, note, dontMiss: [{point, why}], model }
router.post('/ed-encounters/generate', async function (req, res) {
  var start = Date.now();
  try {
    var {
      stage, transcript, chiefComplaint,
      patientAge, patientGender,
      previousNote, physicianMemories, model
    } = req.body;

    if (!chiefComplaint || !chiefComplaint.trim()) {
      return res.status(400).json({ error: 'Chief complaint is required' });
    }
    if (!transcript || !transcript.trim()) {
      return res.status(400).json({ error: 'Transcript is required' });
    }

    var stageNum = parseInt(stage, 10) || 1;

    var context = 'ED ENCOUNTER — STAGE ' + stageNum + '\n';
    context += 'Patient: ' + (patientAge || 'Unknown age') + ', ' + (patientGender || 'Unknown gender') + '\n';
    context += 'Chief Complaint: ' + wrapUserText('chief_complaint', chiefComplaint) + '\n\n';
    context += 'CURRENT STAGE TRANSCRIPT (may include direct physician asides — preserve and route them per the prompt rules):\n'
      + wrapUserText('transcript', transcript) + '\n\n';

    if (previousNote && previousNote.trim() && stageNum > 1) {
      context += 'PREVIOUS-STAGE NOTE (baseline to integrate on top of — do not start fresh):\n'
        + wrapUserText('previous_note', previousNote) + '\n\n';
    }
    if (physicianMemories && physicianMemories.trim()) {
      context += physicianMemories + '\n\n';
    }

    var result = await callAI([
      { role: 'system', content: PROMPTS.edEncounterStaged + INJECTION_GUARD },
      { role: 'user',   content: context }
    ], { model: model, maxTokens: 4000 });

    var parsed = extractJson(result.content);
    if (!parsed || typeof parsed.note !== 'string') {
      // Recovery: if the model returned plain prose, treat the whole response
      // as the note and return an empty don't-miss list rather than 500-ing.
      parsed = { note: String(result.content || '').trim(), dontMiss: [] };
    }
    if (!Array.isArray(parsed.dontMiss)) parsed.dontMiss = [];
    parsed.dontMiss = parsed.dontMiss
      .filter(function (d) { return d && d.point; })
      .map(function (d) { return { point: String(d.point).trim(), why: String(d.why || '').trim() }; });

    var dur = Date.now() - start;
    logger.apiCall(req.user.id, '/api/ed-encounters/generate', {
      model: result.model,
      tokensInput: result.usage && result.usage.input_tokens,
      tokensOutput: result.usage && result.usage.output_tokens,
      duration: dur,
      statusCode: 200
    });
    logger.audit(req.user.id, 'generate_ed_encounter', 'ED encounter stage ' + stageNum, req, { category: 'clinical' });

    res.json({ success: true, note: parsed.note, dontMiss: parsed.dontMiss, model: result.model });
  } catch (e) {
    logger.error('[edEncounters] generate failed', e.message);
    res.status(500).json({ error: 'Request failed' });
  }
});

// ── POST /ed-encounters/finalize — consolidate stages + generate MDM ─
// Two-step server-side flow:
//   1. Consolidate every stage's note + transcript into one polished
//      final clinical note (PROMPTS.edConsolidate, plain text out).
//   2. Generate the 2023 AMA E/M MDM block from that consolidated note
//      (PROMPTS.edFinalize, JSON out).
// Two AI calls so each task gets its own focused prompt — more reliable
// than asking the model for both in one response.
// Body:
//   stages          — array of { transcript, note } in chronological order (required)
//   chiefComplaint  — string, optional but strongly preferred
//   patientAge      — string, optional
//   patientGender   — string, optional
//   model           — optional override
// Returns: { success, finalNote, mdm, model }
router.post('/ed-encounters/finalize', async function (req, res) {
  var start = Date.now();
  try {
    var { stages, chiefComplaint, patientAge, patientGender, model } = req.body;

    if (!Array.isArray(stages) || stages.length === 0) {
      return res.status(400).json({ error: 'stages array is required' });
    }
    var validStages = stages.filter(function (s) { return s && (s.note || s.transcript); });
    if (validStages.length === 0) {
      return res.status(400).json({ error: 'at least one stage must have a note or transcript' });
    }

    // ── Step 1: consolidate ──────────────────────────────────────────
    var consolidateContext = 'PATIENT: ' + (patientAge || 'Unknown age')
      + (patientGender ? ', ' + patientGender : '') + '\n';
    if (chiefComplaint && chiefComplaint.trim()) {
      consolidateContext += 'CHIEF COMPLAINT: ' + wrapUserText('chief_complaint', chiefComplaint) + '\n';
    }
    consolidateContext += '\nSTAGE-BY-STAGE NOTES AND TRANSCRIPTS (chronological):\n\n';
    validStages.forEach(function (s, i) {
      consolidateContext += '=== STAGE ' + (i + 1) + ' ===\n';
      if (s.transcript && s.transcript.trim()) {
        consolidateContext += 'Transcript:\n' + wrapUserText('transcript_' + i, s.transcript) + '\n';
      }
      if (s.note && s.note.trim()) {
        consolidateContext += 'Working note (may include physician edits):\n' + wrapUserText('note_' + i, s.note) + '\n';
      }
      consolidateContext += '\n';
    });

    var consolidateResult = await callAI([
      { role: 'system', content: PROMPTS.edConsolidate + INJECTION_GUARD },
      { role: 'user',   content: consolidateContext }
    ], { model: model, maxTokens: 4000 });

    var finalNote = String(consolidateResult.content || '').trim();
    if (!finalNote) {
      return res.status(502).json({ error: 'Consolidate step returned empty note' });
    }

    // ── Step 2: MDM ──────────────────────────────────────────────────
    var fullTranscript = validStages.map(function (s, i) {
      return '--- Stage ' + (i + 1) + ' ---\n' + (s.transcript || '');
    }).join('\n\n');

    var mdmContext = 'PATIENT: ' + (patientAge || 'Unknown age') + '\n\n';
    mdmContext += 'FINAL CLINICAL NOTE:\n' + wrapUserText('note', finalNote) + '\n\n';
    mdmContext += 'FULL ENCOUNTER TRANSCRIPT (all stages):\n' + wrapUserText('transcript', fullTranscript) + '\n';

    var mdmResult = await callAI([
      { role: 'system', content: PROMPTS.edFinalize + INJECTION_GUARD },
      { role: 'user',   content: mdmContext }
    ], { model: model, maxTokens: 2000 });

    var parsed = extractJson(mdmResult.content);
    if (!parsed || !parsed.mdm) {
      return res.status(502).json({
        error: 'MDM step did not return a parseable JSON block',
        finalNote: finalNote,  // still return the consolidated note so the client doesn't lose work
        raw: mdmResult.content
      });
    }

    var dur = Date.now() - start;
    var inTokens = ((consolidateResult.usage && consolidateResult.usage.input_tokens) || 0)
                 + ((mdmResult.usage         && mdmResult.usage.input_tokens)         || 0);
    var outTokens = ((consolidateResult.usage && consolidateResult.usage.output_tokens) || 0)
                  + ((mdmResult.usage         && mdmResult.usage.output_tokens)         || 0);
    logger.apiCall(req.user.id, '/api/ed-encounters/finalize', {
      model: mdmResult.model,
      tokensInput: inTokens,
      tokensOutput: outTokens,
      duration: dur,
      statusCode: 200
    });
    logger.audit(req.user.id, 'finalize_ed_encounter', 'ED encounter consolidated + MDM (' + validStages.length + ' stages)', req, { category: 'clinical' });

    res.json({ success: true, finalNote: finalNote, mdm: parsed.mdm, model: mdmResult.model });
  } catch (e) {
    logger.error('[edEncounters] finalize failed', e.message);
    res.status(500).json({ error: 'Request failed' });
  }
});

module.exports = router;
