import { randomUUID } from 'node:crypto';
import { Router } from 'express';
import { z } from 'zod';
import { requireAdmin, requireAuth, type AuthenticatedRequest } from './auth';
import { pool } from './db';

export const safetyRouter = Router();

const reportSchema = z.object({
  category: z.enum(['conduct', 'privacy', 'impersonation', 'other']),
  description: z.string().trim().min(20).max(2000),
});

safetyRouter.post('/journeys/:id/reports', requireAuth, async (request: AuthenticatedRequest, response) => {
  const journeyId = z.uuid().safeParse(request.params.id);
  const parsed = reportSchema.safeParse(request.body);
  if (!journeyId.success || !parsed.success) {
    response.status(400).json({ error: 'Invalid report data' }); return;
  }
  const access = await pool.query(
    'SELECT id FROM journeys WHERE id=$1 AND (first_user_id=$2 OR second_user_id=$2)',
    [journeyId.data, request.authUser!.id],
  );
  if (!access.rowCount) { response.status(404).json({ error: 'Journey not found' }); return; }
  const id = randomUUID();
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    const created = await client.query(
      `INSERT INTO safety_reports (id, journey_id, reporter_user_id, category, description)
       VALUES ($1, $2, $3, $4, $5) RETURNING id, status, created_at AS "createdAt"`,
      [id, journeyId.data, request.authUser!.id, parsed.data.category, parsed.data.description],
    );
    await client.query(
      "INSERT INTO audit_events (user_id, event_type, details) VALUES ($1, 'safety_report_created', $2::jsonb)",
      [request.authUser!.id, JSON.stringify({ reportId: id, journeyId: journeyId.data })],
    );
    await client.query('COMMIT');
    response.status(201).json({ report: created.rows[0] });
  } catch (error) { await client.query('ROLLBACK'); throw error; }
  finally { client.release(); }
});

safetyRouter.get('/me/reports', requireAuth, async (request: AuthenticatedRequest, response) => {
  const reports = await pool.query(
    `SELECT id, journey_id AS "journeyId", category, status, created_at AS "createdAt", updated_at AS "updatedAt"
     FROM safety_reports WHERE reporter_user_id=$1 ORDER BY created_at DESC LIMIT 100`,
    [request.authUser!.id],
  );
  response.json({ reports: reports.rows });
});

safetyRouter.get('/admin/reports', requireAuth, requireAdmin, async (_request, response) => {
  const reports = await pool.query(
    `SELECT r.id, r.journey_id AS "journeyId", r.category, r.description, r.status,
            r.admin_note AS "adminNote", r.created_at AS "createdAt", r.updated_at AS "updatedAt",
            reporter.display_name AS "reporterName", reporter.email AS "reporterEmail",
            reviewer.display_name AS "reviewerName"
     FROM safety_reports r
     JOIN users reporter ON reporter.id=r.reporter_user_id
     LEFT JOIN users reviewer ON reviewer.id=r.reviewed_by
     ORDER BY CASE WHEN r.status IN ('open', 'reviewing') THEN 0 ELSE 1 END, r.created_at DESC LIMIT 200`,
  );
  response.json({ reports: reports.rows });
});

const reviewSchema = z.object({
  status: z.enum(['reviewing', 'resolved', 'dismissed']),
  adminNote: z.string().trim().min(3).max(2000),
});

safetyRouter.patch('/admin/reports/:id', requireAuth, requireAdmin, async (request: AuthenticatedRequest, response) => {
  const reportId = z.uuid().safeParse(request.params.id);
  const parsed = reviewSchema.safeParse(request.body);
  if (!reportId.success || !parsed.success) { response.status(400).json({ error: 'Invalid review data' }); return; }
  const client = await pool.connect();
  try {
    await client.query('BEGIN');
    const updated = await client.query(
      `UPDATE safety_reports SET status=$1, admin_note=$2, reviewed_by=$3, updated_at=NOW()
       WHERE id=$4 RETURNING id, status, updated_at AS "updatedAt"`,
      [parsed.data.status, parsed.data.adminNote, request.authUser!.id, reportId.data],
    );
    if (!updated.rowCount) { await client.query('ROLLBACK'); response.status(404).json({ error: 'Report not found' }); return; }
    await client.query(
      "INSERT INTO audit_events (user_id, event_type, details) VALUES ($1, 'safety_report_reviewed', $2::jsonb)",
      [request.authUser!.id, JSON.stringify({ reportId: reportId.data, status: parsed.data.status })],
    );
    await client.query('COMMIT');
    response.json({ report: updated.rows[0] });
  } catch (error) { await client.query('ROLLBACK'); throw error; }
  finally { client.release(); }
});
