import { randomUUID } from 'node:crypto';
import { Router } from 'express';
import { z } from 'zod';
import { requireAuth, type AuthenticatedRequest } from './auth';
import { pool } from './db';
import { hasFourWayMediaConnection } from './familyCallState';
import { authorizeJourney } from './familyJourney';
import { journeyNotificationRecipients, notifyUsers } from './notifications';
import { recordJourneyEvent } from './relationshipEvents';

export const familyMeetingCompletionRouter = Router();

familyMeetingCompletionRouter.post('/journeys/:id/meetings/:meetingId/cancel', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const access = await authorizeJourney(request, response, 'participant');
    const meetingId = z.uuid().safeParse(request.params.meetingId);
    const parsed = z.object({ reason: z.string().trim().max(500).optional().default('') }).safeParse(request.body);
    if (!access || !meetingId.success || !parsed.success) {
      if (access) response.status(400).json({ error: 'Invalid meeting cancellation' }); return;
    }
    const client = await pool.connect();
    try {
      await client.query('BEGIN');
      const result = await client.query(
        `UPDATE meeting_proposals SET status='cancelled'
         WHERE id=$1 AND journey_id=$2 AND status IN ('proposed', 'confirmed')
         RETURNING id,status`, [meetingId.data, access.id],
      );
      if (!result.rowCount) {
        await client.query('ROLLBACK');
        response.status(409).json({ error: 'Meeting cannot be cancelled in its current state' }); return;
      }
      await client.query(
        'UPDATE meeting_call_sessions SET left_at=NOW() WHERE meeting_id=$1 AND left_at IS NULL',
        [meetingId.data],
      );
      await client.query(
        "INSERT INTO audit_events (user_id,event_type,details) VALUES ($1,'meeting_cancelled',$2::jsonb)",
        [request.authUser!.id, JSON.stringify({ journeyId: access.id, meetingId: meetingId.data,
          reason: parsed.data.reason })],
      );
      await client.query('COMMIT');
      await recordJourneyEvent(access.id, request.authUser!.id, 'meeting_cancelled', {
        meetingId: meetingId.data, reason: parsed.data.reason,
      });
      const recipients = await journeyNotificationRecipients(access.id, request.authUser!.id);
      await notifyUsers(recipients.userIds, {
        type: 'meeting_cancelled', title: 'أُلغي موعد مكالمة الفيديو',
        body: parsed.data.reason ? `أُلغي الموعد. السبب: ${parsed.data.reason}` : 'أُلغي الموعد ويمكن اقتراح موعد آخر.',
        journeyId: access.id, requestId: recipients.requestId,
        dedupeKey: `meeting-cancelled:${meetingId.data}`,
      });
      response.json({ meeting: result.rows[0] });
    } catch (error) { await client.query('ROLLBACK'); throw error; }
    finally { client.release(); }
  });

familyMeetingCompletionRouter.post('/journeys/:id/meetings/:meetingId/attendance', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const access = await authorizeJourney(request, response, 'participant');
    const meetingId = z.uuid().safeParse(request.params.meetingId);
    if (!access || !meetingId.success) return;
    const client = await pool.connect();
    try {
      await client.query('BEGIN');
      const meeting = await client.query<{ status: string; starts_at: Date; video_required: boolean }>(
        'SELECT status,starts_at,video_required FROM meeting_proposals WHERE id=$1 AND journey_id=$2 FOR UPDATE',
        [meetingId.data, access.id],
      );
      if (meeting.rows[0]?.status !== 'confirmed' || meeting.rows[0].starts_at.getTime() > Date.now()) {
        await client.query('ROLLBACK');
        response.status(409).json({ error: 'Meeting is not ready to be marked complete' }); return;
      }
      if (meeting.rows[0].video_required
        && !await hasFourWayMediaConnection(access.id, meetingId.data)) {
        await client.query('ROLLBACK');
        response.status(409).json({
          error: 'All required call participants must establish a connected call before attendance is confirmed',
        });
        return;
      }
      await client.query(
        'INSERT INTO meeting_attendance (meeting_id,user_id) VALUES ($1,$2) ON CONFLICT DO NOTHING',
        [meetingId.data, request.authUser!.id],
      );
      const attendance = await client.query<{ count: number }>(
        'SELECT COUNT(*)::int AS count FROM meeting_attendance WHERE meeting_id=$1',
        [meetingId.data],
      );
      if (attendance.rows[0].count === 2) {
        await client.query("UPDATE meeting_proposals SET status='completed' WHERE id=$1", [meetingId.data]);
        await client.query(
          'INSERT INTO decision_rounds (id,journey_id,meeting_id) VALUES ($1,$2,$3)',
          [randomUUID(), access.id, meetingId.data],
        );
      }
      await client.query('COMMIT');
      if (attendance.rows[0].count === 2) {
        await recordJourneyEvent(access.id, request.authUser!.id, 'meeting_completed', {
          meetingId: meetingId.data,
        });
      }
      response.json({ attendanceCount: attendance.rows[0].count,
        decisionReady: attendance.rows[0].count === 2 });
    } catch (error) { await client.query('ROLLBACK'); throw error; }
    finally { client.release(); }
  });
