import { randomUUID } from 'node:crypto';
import { Router, type Response } from 'express';
import { z } from 'zod';
import { requireAuth, type AuthenticatedRequest } from './auth';
import { pool } from './db';
import { recordRequestEvent } from './relationshipEvents';
import { notifyUsers } from './notifications';

export const journeyRequestDecisionRouter = Router();

const requireCandidate = (request: AuthenticatedRequest, response: Response): boolean => {
  if (request.authUser?.role === 'user' && request.authUser.accountType === 'candidate') return true;
  response.status(403).json({ error: 'Candidate account required' });
  return false;
};

const requestFields = `r.id, r.sender_user_id AS "senderUserId",
  r.recipient_user_id AS "recipientUserId", r.status,
  r.created_at AS "createdAt", r.updated_at AS "updatedAt"`;

const decisionSchema = z.object({ action: z.enum(['accept', 'decline', 'withdraw']) });

journeyRequestDecisionRouter.post('/requests/:id/decision', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    if (!requireCandidate(request, response)) return;
    const parsed = decisionSchema.safeParse(request.body);
    const id = z.uuid().safeParse(request.params.id);
    if (!parsed.success || !id.success) {
      response.status(400).json({ error: 'Invalid request decision' }); return;
    }
    const action = parsed.data.action;
    const status = action === 'accept' ? 'accepted' : action === 'decline' ? 'declined' : 'withdrawn';
    const participantColumn = action === 'withdraw' ? 'sender_user_id' : 'recipient_user_id';
    const client = await pool.connect();
    try {
      await client.query('BEGIN');
      const updated = await client.query(
        `UPDATE engagement_requests r SET status=$1, updated_at=NOW()
         WHERE r.id=$2 AND r.status='pending' AND r.${participantColumn}=$3
           AND ($4::text <> 'accept' OR NOT EXISTS (
             SELECT 1 FROM user_blocks b WHERE
               (b.blocker_user_id=r.sender_user_id AND b.blocked_user_id=r.recipient_user_id)
               OR (b.blocker_user_id=r.recipient_user_id AND b.blocked_user_id=r.sender_user_id)))
         RETURNING ${requestFields}`,
        [status, id.data, request.authUser!.id, action],
      );
      if (!updated.rowCount) {
        await client.query('ROLLBACK');
        response.status(404).json({ error: 'Pending request not found for this account' }); return;
      }
      let journey: Record<string, unknown> | null = null;
      if (action === 'accept') {
        const created = await client.query(
          `INSERT INTO journeys (id, request_id, first_user_id, second_user_id)
           VALUES ($1, $2, $3, $4)
           RETURNING id, request_id AS "requestId", status, created_at AS "createdAt"`,
          [randomUUID(), id.data, updated.rows[0].senderUserId, updated.rows[0].recipientUserId],
        );
        journey = created.rows[0];
      }
      await client.query(
        'INSERT INTO audit_events (user_id, event_type, details) VALUES ($1, $2, $3::jsonb)',
        [request.authUser!.id, `engagement_request_${status}`, JSON.stringify({ requestId: id.data })],
      );
      await client.query('COMMIT');
      await recordRequestEvent(id.data, request.authUser!.id, `request_${status}`);
      const targetId = action === 'withdraw'
        ? updated.rows[0].recipientUserId : updated.rows[0].senderUserId;
      const decisionText = action === 'accept' ? 'قُبل طلب التعارف وبدأ المسار.'
        : action === 'decline' ? 'تم الاعتذار عن طلب التعارف.' : 'سُحب طلب التعارف.';
      await notifyUsers([targetId], {
        type: 'engagement_decision', title: 'تحديث طلب التعارف', body: decisionText,
        requestId: id.data, dedupeKey: `engagement-decision:${id.data}:${status}`,
      });
      response.json({ request: updated.rows[0], journey });
    } catch (error) {
      await client.query('ROLLBACK');
      throw error;
    } finally {
      client.release();
    }
  });

journeyRequestDecisionRouter.get('/journeys', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    if (request.authUser?.role !== 'user') {
      response.status(403).json({ error: 'User account required' }); return;
    }
    const result = await pool.query(
      `SELECT j.id, j.request_id AS "requestId", j.status,
         j.created_at AS "createdAt",
         CASE WHEN j.first_user_id=$1 OR j.second_user_id=$1 THEN 'participant'
              ELSE m.permission END AS "myPermission",
         EXISTS (SELECT 1 FROM journey_call_guardians g WHERE g.journey_id=j.id
           AND g.guardian_user_id=$1 AND g.selection_mode='exception') AS "isRepresentative",
         EXISTS (SELECT 1 FROM journey_call_guardians g WHERE g.journey_id=j.id
           AND g.guardian_user_id=$1 AND g.selection_mode='guardian') AS "isGuardian",
         (SELECT participant.display_name FROM journey_call_guardians g
           JOIN users participant ON participant.id=g.participant_user_id
           WHERE g.journey_id=j.id AND g.guardian_user_id=$1 LIMIT 1) AS "guardianForName",
         CASE WHEN j.first_user_id=$1 THEN second_profile.display_name
              WHEN j.second_user_id=$1 THEN first_profile.display_name
              ELSE first_profile.display_name || ' / ' || second_profile.display_name END AS "counterpartName"
       FROM journeys j
       JOIN profiles first_profile ON first_profile.user_id=j.first_user_id
       JOIN profiles second_profile ON second_profile.user_id=j.second_user_id
       LEFT JOIN journey_memberships m ON m.journey_id=j.id AND m.user_id=$1 AND m.is_active
       WHERE j.first_user_id=$1 OR j.second_user_id=$1 OR m.user_id=$1
       ORDER BY j.created_at DESC LIMIT 100`,
      [request.authUser!.id],
    );
    response.json({ journeys: result.rows });
  });
