'use strict';

const { getAllowedOrigin } = require('./auth');
const {
  jsonResponse,
  parseLimit,
  parseMultipart,
  readBody,
} = require('./api-utils');

function ensureListeningBrain(res, brain, ensureBrainInit) {
  if (!brain || !ensureBrainInit()) {
    jsonResponse(res, { error: 'Brain module not available' }, 503);
    return false;
  }
  return true;
}

function handleListeningApi(req, res, url, { brain, ensureBrainInit }) {
  const p = url.pathname;
  const m = req.method;
  const params = url.searchParams;

  if (!p.startsWith('/api/wall-e/listening/')) return false;

  if (p === '/api/wall-e/listening/start' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        const engine = require('../listening/engine');
        const result = engine.startRecording(body.mode || 'meeting', body.title, body.calendarEventId);
        jsonResponse(res, { data: result });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/stop' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        const engine = require('../listening/engine');
        const result = engine.stopRecording(body.recordingId);
        jsonResponse(res, { data: result });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/upload' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    const chunks = [];
    let size = 0;
    let aborted = false;
    req.on('data', chunk => {
      if (aborted) return;
      size += chunk.length;
      if (size > 50 * 1024 * 1024) {
        aborted = true;
        jsonResponse(res, { error: 'Upload too large (50MB limit)' }, 413);
        req.destroy();
        return;
      }
      chunks.push(chunk);
    });
    req.on('end', () => {
      if (aborted) return;
      try {
        const raw = Buffer.concat(chunks);
        const contentType = req.headers['content-type'] || '';
        const engine = require('../listening/engine');
        const boundaryMatch = contentType.match(/boundary=(?:"([^"]+)"|([^\s;]+))/);
        if (!boundaryMatch) {
          return jsonResponse(res, { error: 'Missing multipart boundary' }, 400);
        }
        const boundary = boundaryMatch[1] || boundaryMatch[2];
        const parts = parseMultipart(raw, boundary);
        const recordingId = parts.recordingId;
        const audioBuffer = parts.audio;
        if (!recordingId || !audioBuffer) {
          return jsonResponse(res, { error: 'Missing recordingId or audio data' }, 400);
        }
        const result = engine.uploadChunk(recordingId, audioBuffer);
        jsonResponse(res, { ok: true, chunkIndex: result.index, totalSize: result.totalSize });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    });
    return true;
  }

  if (p === '/api/wall-e/listening/interim' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        const engine = require('../listening/engine');
        engine.processInterimText(body.recordingId, body.text, body.isFinal, body.timestamp);
        jsonResponse(res, { ok: true });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/refine' && m === 'POST') {
    readBody(req).then(async body => {
      try {
        const { refine } = require('../listening/refine');
        const result = await refine(body.text, body.lang, body.context);
        jsonResponse(res, { data: result });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/recordings' && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const engine = require('../listening/engine');
      const limit = parseLimit(params, 50);
      const offset = parseInt(params.get('offset')) || 0;
      const status = params.get('status') || null;
      const mode = params.get('mode') || null;
      const data = engine.listRecordings({ limit, offset, status, mode });
      jsonResponse(res, { data });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p.startsWith('/api/wall-e/listening/recordings/') && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const id = p.split('/').pop();
      const engine = require('../listening/engine');
      const data = engine.getRecordingDetail(id);
      if (!data) return jsonResponse(res, { error: 'Not found' }, 404), true;
      jsonResponse(res, { data });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p.startsWith('/api/wall-e/listening/recordings/') && m === 'DELETE') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const id = p.split('/').pop();
      const engine = require('../listening/engine');
      engine.deleteRecording(id);
      jsonResponse(res, { ok: true });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p === '/api/wall-e/listening/speakers' && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const rows = brain.getDb().prepare('SELECT * FROM speaker_profiles ORDER BY times_identified DESC').all();
      jsonResponse(res, { data: rows });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p === '/api/wall-e/listening/speakers/enroll' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        if (!body.name) return jsonResponse(res, { error: 'name required' }, 400);
        const diarize = require('../listening/diarize');
        const result = diarize.enrollSpeaker(body.name, body.recordingId || '00000000-0000-0000-0000-000000000000');
        const row = brain.getDb().prepare('SELECT * FROM speaker_profiles WHERE id = ?').get(result.id);
        jsonResponse(res, { data: row });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/label-speakers' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        if (!body.recordingId || !body.labels) return jsonResponse(res, { error: 'recordingId and labels required' }, 400);
        const diarize = require('../listening/diarize');
        const result = diarize.applyLabels(body.recordingId, body.labels);
        jsonResponse(res, { ok: true, data: result });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p.startsWith('/api/wall-e/listening/recording-speakers/') && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const id = p.split('/').pop();
      const diarize = require('../listening/diarize');
      jsonResponse(res, { data: diarize.getRecordingSpeakers(id) });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p === '/api/wall-e/listening/suggest-speakers' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        if (!body.recordingId) return jsonResponse(res, { error: 'recordingId required' }, 400);
        const diarize = require('../listening/diarize');
        jsonResponse(res, { data: diarize.suggestMatches(body.recordingId) });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/generate-notes' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(async body => {
      try {
        if (!body.recordingId) return jsonResponse(res, { error: 'recordingId required' }, 400);
        const notes = require('../listening/notes');
        const result = await notes.generateMeetingNotes(body.recordingId);
        jsonResponse(res, { data: result });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/generate-email' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(async body => {
      try {
        if (!body.recordingId) return jsonResponse(res, { error: 'recordingId required' }, 400);
        const notes = require('../listening/notes');
        const result = await notes.generateEmailDraft(body.recordingId, body);
        jsonResponse(res, { data: result });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/process' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(async body => {
      try {
        if (!body.recordingId) return jsonResponse(res, { error: 'recordingId required' }, 400);
        const notes = require('../listening/notes');
        const result = await notes.processRecording(body.recordingId);
        jsonResponse(res, { data: result });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p.startsWith('/api/wall-e/listening/notes/') && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const id = p.split('/').pop();
      const notes = require('../listening/notes');
      jsonResponse(res, { data: notes.getOutputs(id) });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p === '/api/wall-e/listening/calendar-events' && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const calendar = require('../listening/calendar');
      const limit = parseInt(params.get('limit')) || 10;
      jsonResponse(res, { data: calendar.getUpcomingMeetings(limit) });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p === '/api/wall-e/listening/current-meeting' && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const calendar = require('../listening/calendar');
      jsonResponse(res, { data: calendar.detectCurrentMeeting() });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p === '/api/wall-e/listening/calendar-sync' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(async body => {
      try {
        const calendar = require('../listening/calendar');
        const result = await calendar.syncUpcomingMeetings(body.windowHours || 2);
        jsonResponse(res, { data: result });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/config' && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const calendar = require('../listening/calendar');
      const stt = require('../listening/stt');
      jsonResponse(res, { data: {
        calendar: calendar.getConfig(),
        stt: { configured: stt.hasApiKey() },
      }});
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p === '/api/wall-e/listening/config' && m === 'PUT') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        if (body.calendarSource) {
          const calendar = require('../listening/calendar');
          calendar.configureSource(body.calendarSource, body.calendarConfig || {});
        }
        if (body.assemblyaiKey) {
          const stt = require('../listening/stt');
          stt.setApiKey(body.assemblyaiKey);
        }
        jsonResponse(res, { ok: true });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p === '/api/wall-e/listening/transcribe' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        const stt = require('../listening/stt');
        const check = stt.canTranscribe(body.recordingId);
        if (!check.can) return jsonResponse(res, { error: check.reason }, 400);
        stt.transcribeRecording(body.recordingId, {
          speakerLabels: body.speakerLabels !== false,
          speakersExpected: body.speakersExpected,
        }).catch(err => console.error('[listening] Transcription failed:', err.message));
        jsonResponse(res, { ok: true, message: 'Transcription started' });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  if (p.startsWith('/api/wall-e/listening/transcribe-progress/') && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    const id = p.split('/').pop();
    res.writeHead(200, {
      'Content-Type': 'text/event-stream',
      'Cache-Control': 'no-cache',
      'Connection': 'keep-alive',
      'Access-Control-Allow-Origin': getAllowedOrigin(req),
    });

    const stt = require('../listening/stt');
    let closed = false;
    req.on('close', () => { closed = true; });

    const sendProgress = () => {
      if (closed) return;
      const progress = stt.getProgress(id);
      if (progress) {
        res.write('data: ' + JSON.stringify(progress) + '\n\n');
        if (progress.status === 'done' || progress.status === 'error') {
          res.end();
          return;
        }
      }
      setTimeout(sendProgress, 1000);
    };
    sendProgress();
    return true;
  }

  if (p === '/api/wall-e/listening/stt-status' && m === 'GET') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    try {
      const stt = require('../listening/stt');
      jsonResponse(res, { data: { configured: stt.hasApiKey() } });
    } catch (e) {
      jsonResponse(res, { error: e.message }, 500);
    }
    return true;
  }

  if (p === '/api/wall-e/listening/stt-key' && m === 'POST') {
    if (!ensureListeningBrain(res, brain, ensureBrainInit)) return true;
    readBody(req).then(body => {
      try {
        if (!body.key) return jsonResponse(res, { error: 'key required' }, 400);
        const stt = require('../listening/stt');
        stt.setApiKey(body.key);
        jsonResponse(res, { ok: true });
      } catch (e) {
        jsonResponse(res, { error: e.message }, 500);
      }
    }).catch(e => jsonResponse(res, { error: e.message }, 500));
    return true;
  }

  return false;
}

module.exports = { handleListeningApi };
