'use strict';

const feedbackStore = require('./feedback-store');

function jsonResponse(res, status, data) {
  const body = JSON.stringify(data);
  res.writeHead(status, {
    'Content-Type': 'application/json',
    'Content-Length': Buffer.byteLength(body),
  });
  res.end(body);
}

function readJsonBody(req, maxBytes = 1024 * 1024) {
  return new Promise((resolve, reject) => {
    const chunks = [];
    let size = 0;
    req.on('data', (chunk) => {
      size += chunk.length;
      if (size > maxBytes) {
        const err = new Error('Body too large');
        err.statusCode = 413;
        reject(err);
        req.destroy();
        return;
      }
      chunks.push(chunk);
    });
    req.on('end', () => {
      try {
        const raw = Buffer.concat(chunks).toString('utf8');
        resolve(raw ? JSON.parse(raw) : {});
      } catch (err) {
        err.statusCode = 400;
        reject(err);
      }
    });
    req.on('error', reject);
  });
}

function extractFeedbackId(pathname) {
  const m = pathname.match(/^\/api\/feedback\/([^/]+)(?:\/|$)/);
  return m ? decodeURIComponent(m[1]) : '';
}

function handleFeedbackApi(req, res, url, { db, walleClient, remoteFeedbackClient, telemetry } = {}) {
  if (!url.pathname.startsWith('/api/feedback')) return false;
  if (!db) {
    jsonResponse(res, 503, { ok: false, error: 'Feedback DB unavailable' });
    return true;
  }
  feedbackStore.ensureFeedbackSchema(db);

  try {
    if (url.pathname === '/api/feedback/capabilities' && req.method === 'GET') {
      jsonResponse(res, 200, {
        ok: true,
        attachments: true,
        screenshots: true,
        triage: true,
        context_preview: true,
        remote_feedback: true,
        walle_ingest: true,
        inbox_available: false,
        admin_board: {
          implemented: false,
          recommended_gate: 'separate_admin_token_plus_owner_allowlist',
        },
      });
      return true;
    }

    if (url.pathname === '/api/feedback/drafts' && req.method === 'POST') {
      readJsonBody(req).then((body) => {
        const draft = feedbackStore.createFeedbackDraft(db, body);
        const triaged = feedbackStore.triageFeedback(db, draft.id);
        telemetry?.track?.('ctm_feedback_created', {
          source: triaged.source,
          surface: triaged.surface,
          type: triaged.type,
          has_session: triaged.ctm_session_id ? 1 : 0,
        });
        jsonResponse(res, 201, { ok: true, feedback: triaged });
      }).catch((err) => jsonResponse(res, err.statusCode || 400, { ok: false, error: err.message }));
      return true;
    }

    const feedbackId = extractFeedbackId(url.pathname);
    if (!feedbackId) {
      jsonResponse(res, 404, { ok: false, error: 'Not found' });
      return true;
    }

    if (url.pathname === `/api/feedback/${encodeURIComponent(feedbackId)}` && req.method === 'GET') {
      const feedback = feedbackStore.getFeedback(db, feedbackId);
      if (!feedback) return jsonResponse(res, 404, { ok: false, error: 'Feedback not found' });
      jsonResponse(res, 200, { ok: true, feedback });
      return true;
    }

    if (url.pathname === `/api/feedback/${encodeURIComponent(feedbackId)}` && req.method === 'PUT') {
      readJsonBody(req).then((body) => {
        const feedback = feedbackStore.updateFeedback(db, feedbackId, body);
        if (!feedback) return jsonResponse(res, 404, { ok: false, error: 'Feedback not found' });
        jsonResponse(res, 200, { ok: true, feedback });
      }).catch((err) => jsonResponse(res, err.statusCode || 400, { ok: false, error: err.message }));
      return true;
    }

    if (url.pathname === `/api/feedback/${encodeURIComponent(feedbackId)}/attachments` && req.method === 'POST') {
      readJsonBody(req).then((body) => {
        const feedback = feedbackStore.addAttachment(db, feedbackId, body);
        if (!feedback) return jsonResponse(res, 404, { ok: false, error: 'Feedback not found' });
        const triaged = feedbackStore.triageFeedback(db, feedbackId);
        jsonResponse(res, 201, { ok: true, feedback: triaged });
      }).catch((err) => jsonResponse(res, err.statusCode || 400, { ok: false, error: err.message }));
      return true;
    }

    const attachmentMatch = url.pathname.match(/^\/api\/feedback\/([^/]+)\/attachments\/([^/]+)$/);
    if (attachmentMatch && req.method === 'DELETE') {
      const removed = feedbackStore.removeAttachment(db, feedbackId, decodeURIComponent(attachmentMatch[2]));
      jsonResponse(res, removed ? 200 : 404, { ok: removed });
      return true;
    }

    if (url.pathname === `/api/feedback/${encodeURIComponent(feedbackId)}/triage` && req.method === 'POST') {
      readJsonBody(req).then((body) => {
        if (body && Object.keys(body).length) feedbackStore.updateFeedback(db, feedbackId, body);
        const feedback = feedbackStore.triageFeedback(db, feedbackId);
        if (!feedback) return jsonResponse(res, 404, { ok: false, error: 'Feedback not found' });
        jsonResponse(res, 200, { ok: true, feedback, triage: feedback.triage_result });
      }).catch((err) => jsonResponse(res, err.statusCode || 400, { ok: false, error: err.message }));
      return true;
    }

    if (url.pathname === `/api/feedback/${encodeURIComponent(feedbackId)}/context-preview` && req.method === 'GET') {
      const feedback = feedbackStore.refreshContextItems(db, feedbackId);
      if (!feedback) return jsonResponse(res, 404, { ok: false, error: 'Feedback not found' });
      jsonResponse(res, 200, {
        ok: true,
        feedback_id: feedbackId,
        context_items: feedback.context_items,
        evidence_manifest: feedbackStore._private.evidenceManifest(feedback),
      });
      return true;
    }

    if (url.pathname === `/api/feedback/${encodeURIComponent(feedbackId)}/context-items` && req.method === 'POST') {
      readJsonBody(req).then((body) => {
        const feedback = feedbackStore.updateContextItems(db, feedbackId, body.items || []);
        if (!feedback) return jsonResponse(res, 404, { ok: false, error: 'Feedback not found' });
        jsonResponse(res, 200, { ok: true, feedback, evidence_manifest: feedbackStore._private.evidenceManifest(feedback) });
      }).catch((err) => jsonResponse(res, err.statusCode || 400, { ok: false, error: err.message }));
      return true;
    }

    if (url.pathname === `/api/feedback/${encodeURIComponent(feedbackId)}/clarifications` && req.method === 'POST') {
      readJsonBody(req).then((body) => {
        const feedback = feedbackStore.appendClarification(db, feedbackId, body.message || body.text || '');
        if (!feedback) return jsonResponse(res, 404, { ok: false, error: 'Feedback not found' });
        jsonResponse(res, 200, { ok: true, feedback, triage: feedback.triage_result });
      }).catch((err) => jsonResponse(res, err.statusCode || 400, { ok: false, error: err.message }));
      return true;
    }

    if (url.pathname === `/api/feedback/${encodeURIComponent(feedbackId)}/submit` && req.method === 'POST') {
      readJsonBody(req).then(async (body) => {
        if (Array.isArray(body.context_items)) feedbackStore.updateContextItems(db, feedbackId, body.context_items);
        if (body && Object.keys(body).some((k) => !['context_items', 'send_to_remote', 'send_to_walle'].includes(k))) {
          feedbackStore.updateFeedback(db, feedbackId, body);
        }
        let feedback = feedbackStore.submitFeedback(db, feedbackId);
        if (!feedback) return jsonResponse(res, 404, { ok: false, error: 'Feedback not found' });

        const remoteConsent = feedback.consent_level === 'maintainer_report'
          || feedback.consent_level === 'diagnostic_bundle'
          || feedback.consent_level === 'anonymous_aggregate';
        const shouldSendRemote = body.send_to_remote !== false && remoteConsent;
        let remote = {
          ok: false,
          skipped: true,
          reason: remoteConsent ? 'remote_unavailable' : feedback.consent_level,
        };
        if (shouldSendRemote && remoteFeedbackClient?.submitFeedback) {
          const payload = feedbackStore.buildRemotePayload(feedback);
          try {
            remote = await remoteFeedbackClient.submitFeedback(payload);
            feedback = feedbackStore.markRemoteResult(db, feedbackId, remote);
          } catch (err) {
            remote = { ok: false, error: err.message };
            feedback = feedbackStore.markRemoteResult(db, feedbackId, remote);
          }
        }

        const shouldSendToWalle = body.send_to_walle === true || feedback.consent_level === 'local_walle';
        let walle = {
          ok: false,
          skipped: true,
          reason: shouldSendToWalle ? 'walle_unavailable' : feedback.consent_level,
        };
        if (shouldSendToWalle && walleClient?.requestJson) {
          const payload = feedbackStore.buildWallePayload(feedback);
          try {
            const upstream = await walleClient.requestJson('/api/wall-e/feedback/ingest', {
              method: 'POST',
              body: payload,
            });
            walle = upstream.json || { ok: upstream.status >= 200 && upstream.status < 300, status: upstream.status };
            feedback = feedbackStore.markWalleResult(db, feedbackId, walle);
          } catch (err) {
            walle = { ok: false, error: err.message };
            feedback = feedbackStore.markWalleResult(db, feedbackId, walle);
          }
        }

        telemetry?.track?.('ctm_feedback_submitted', {
          type: feedback.type,
          status: feedback.status,
          consent: feedback.consent_level,
          remote: remote.ok ? 1 : 0,
          walle: walle.ok ? 1 : 0,
        });
        jsonResponse(res, 200, { ok: true, feedback, remote, walle });
      }).catch((err) => jsonResponse(res, err.statusCode || 400, { ok: false, error: err.message }));
      return true;
    }

    jsonResponse(res, 404, { ok: false, error: 'Feedback route not found' });
    return true;
  } catch (err) {
    jsonResponse(res, 500, { ok: false, error: err.message });
    return true;
  }
}

module.exports = {
  handleFeedbackApi,
  _private: { readJsonBody, jsonResponse },
};
