← back to Norma

app/api/email-analyzer/drafts/route.ts

178 lines

/**
 * GET    /api/email-analyzer/drafts — list recent analyzer sessions (grouped by session_id)
 * POST   /api/email-analyzer/drafts — save a new version
 * DELETE /api/email-analyzer/drafts?session_id=X — delete ALL versions of a session
 */

import { NextRequest, NextResponse } from 'next/server';
import { query } from '@/lib/db';
import { requireRole } from '@/lib/require-role';
import { getOrgId } from '@/lib/orgId';

export async function GET(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  try {
    const { searchParams } = new URL(request.url);
    const sessionId = searchParams.get('session_id');
    const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;

    let limitParam = parseInt(searchParams.get('limit') || '20', 10);
    if (isNaN(limitParam) || limitParam < 1) limitParam = 20;
    if (limitParam > 100) limitParam = 100;

    if (sessionId) {
      // Get all versions for a specific session
      const conditions: string[] = ['session_id = $1'];
      const values: unknown[] = [sessionId];
      let paramIdx = 2;

      if (orgId) {
        conditions.push(`org_id = $${paramIdx}`);
        values.push(orgId);
        paramIdx++;
      }

      const result = await query(
        `SELECT * FROM email_analyzer_drafts
         WHERE ${conditions.join(' AND ')}
         ORDER BY version_number ASC`,
        values,
      );

      return NextResponse.json({ drafts: result.rows });
    }

    // List recent sessions (latest version per session)
    const conditions: string[] = [];
    const values: unknown[] = [];
    let paramIdx = 1;

    if (orgId) {
      conditions.push(`org_id = $${paramIdx}`);
      values.push(orgId);
      paramIdx++;
    }

    const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : '';

    const result = await query(
      `SELECT DISTINCT ON (session_id)
              id, org_id, session_id, version_number, label, tone,
              paragraph_count, word_count, created_by, created_at,
              LEFT(original_email, 200) AS original_preview
       FROM email_analyzer_drafts
       ${whereClause}
       ORDER BY session_id, version_number DESC`,
      values,
    );

    // Sort by created_at DESC and limit
    const sorted = result.rows
      .sort((a, b) => new Date(b.created_at).getTime() - new Date(a.created_at).getTime())
      .slice(0, limitParam);

    return NextResponse.json({ sessions: sorted });
  } catch (err) {
    console.error('[email-analyzer/drafts] GET error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to fetch analyzer drafts' }, { status: 500 });
  }
}

export async function POST(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  try {
    const body = await request.json();
    const {
      originalEmail,
      currentVersion,
      versionNumber,
      label,
      tone,
      paragraphCount,
      wordCount,
      chatHistory,
      sessionId,
      isFavorite,
      notes,
      subjectLine,
      score,
    } = body;

    if (!originalEmail || !currentVersion || !sessionId) {
      return NextResponse.json(
        { error: 'originalEmail, currentVersion, and sessionId are required' },
        { status: 400 },
      );
    }

    const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;

    const result = await query(
      `INSERT INTO email_analyzer_drafts
         (org_id, original_email, current_version, version_number, label, tone,
          paragraph_count, word_count, chat_history, session_id, created_by,
          is_favorite, notes, subject_line, score)
       VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13, $14, $15)
       RETURNING *`,
      [
        orgId,
        originalEmail,
        currentVersion,
        versionNumber || 1,
        label || null,
        tone || null,
        paragraphCount || null,
        wordCount || null,
        JSON.stringify(chatHistory || []),
        sessionId,
        auth.username,
        Boolean(isFavorite),
        notes || null,
        subjectLine || null,
        typeof score === 'number' ? Math.max(0, Math.min(100, Math.round(score))) : null,
      ],
    );

    return NextResponse.json({ draft: result.rows[0] }, { status: 201 });
  } catch (err) {
    console.error('[email-analyzer/drafts] POST error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to save analyzer draft' }, { status: 500 });
  }
}

export async function DELETE(request: NextRequest) {
  const auth = requireRole(request, 'admin', 'staff');
  if (auth instanceof NextResponse) return auth;

  try {
    const { searchParams } = new URL(request.url);
    const sessionId = searchParams.get('session_id');
    if (!sessionId) {
      return NextResponse.json({ error: 'session_id is required' }, { status: 400 });
    }

    const orgId = auth.role === 'admin' ? getOrgId(request) : auth.orgId;

    const conditions: string[] = ['session_id = $1'];
    const values: unknown[] = [sessionId];
    if (orgId) {
      conditions.push('org_id = $2');
      values.push(orgId);
    }

    const result = await query(
      `DELETE FROM email_analyzer_drafts WHERE ${conditions.join(' AND ')} RETURNING id`,
      values,
    );

    return NextResponse.json({ deleted: result.rows.length });
  } catch (err) {
    console.error('[email-analyzer/drafts] DELETE error:', (err as Error).message);
    return NextResponse.json({ error: 'Failed to delete analyzer session' }, { status: 500 });
  }
}