import { Router } from 'express';
import { z } from 'zod';
import { requireAuth, type AuthenticatedRequest } from './auth';
import { pool } from './db';
import { authorizeJourney } from './familyJourney';

export const familyContactRouter = Router();

const contactFieldSchema = z.enum(['email', 'phone']);
const contactValueSchema = {
  email: z.email().max(160),
  phone: z.string().regex(/^\+[1-9]\d{6,14}$/),
};

familyContactRouter.get('/journeys/:id/contact', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const access = await authorizeJourney(request, response, 'participantRead');
    if (!access) return;
    response.setHeader('Cache-Control', 'no-store');
    const grants = await pool.query<{
      user_id: string;
      field: 'email' | 'phone';
      value: string;
    }>(
      `SELECT g.user_id, g.field, g.value
       FROM journey_contact_grants g JOIN journeys j ON j.id=g.journey_id AND j.status='active'
       WHERE g.journey_id=$1 AND g.user_id = ANY($2::uuid[])`,
      [access.id, [access.first_user_id, access.second_user_id]],
    );
    const mine = grants.rows.filter((row) => row.user_id === request.authUser!.id);
    const counterpart = grants.rows.filter((row) => row.user_id !== request.authUser!.id);
    response.json({
      closed: access.status === 'closed',
      fields: (['email', 'phone'] as const).map((field) => {
        const myGrant = mine.find((row) => row.field === field);
        const otherGrant = counterpart.find((row) => row.field === field);
        return {
          field,
          myValue: myGrant?.value ?? null,
          counterpartReady: Boolean(otherGrant),
          counterpartValue: myGrant && otherGrant ? otherGrant.value : null,
        };
      }),
    });
  });

familyContactRouter.put('/journeys/:id/contact/:field', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const access = await authorizeJourney(request, response, 'participant');
    const field = contactFieldSchema.safeParse(request.params.field);
    if (!access || !field.success) {
      if (access && !field.success) response.status(400).json({ error: 'Invalid contact field' });
      return;
    }
    const value = contactValueSchema[field.data].safeParse(request.body?.value);
    if (!value.success) {
      response.status(400).json({ error: 'Invalid contact value' }); return;
    }
    const client = await pool.connect();
    try {
      await client.query('BEGIN');
      const active = await client.query(
        "SELECT id FROM journeys WHERE id=$1 AND status='active' FOR UPDATE", [access.id],
      );
      if (!active.rowCount) {
        await client.query('ROLLBACK');
        response.status(409).json({ error: 'Journey is closed' }); return;
      }
      await client.query(
        `INSERT INTO journey_contact_grants (journey_id, user_id, field, value)
         VALUES ($1, $2, $3, $4)
         ON CONFLICT (journey_id, user_id, field)
         DO UPDATE SET value=EXCLUDED.value, granted_at=NOW()`,
        [access.id, request.authUser!.id, field.data, value.data],
      );
      await client.query(
        "INSERT INTO audit_events (user_id, event_type, details) VALUES ($1, 'contact_granted', $2::jsonb)",
        [request.authUser!.id, JSON.stringify({ journeyId: access.id, field: field.data })],
      );
      await client.query('COMMIT');
      response.json({ granted: true });
    } catch (error) {
      await client.query('ROLLBACK');
      throw error;
    } finally {
      client.release();
    }
  });

familyContactRouter.delete('/journeys/:id/contact/:field', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const access = await authorizeJourney(request, response, 'participantRead');
    const field = contactFieldSchema.safeParse(request.params.field);
    if (!access || !field.success) {
      if (access && !field.success) response.status(400).json({ error: 'Invalid contact field' });
      return;
    }
    await pool.query(
      'DELETE FROM journey_contact_grants WHERE journey_id=$1 AND user_id=$2 AND field=$3',
      [access.id, request.authUser!.id, field.data],
    );
    await pool.query(
      "INSERT INTO audit_events (user_id, event_type, details) VALUES ($1, 'contact_revoked', $2::jsonb)",
      [request.authUser!.id, JSON.stringify({ journeyId: access.id, field: field.data })],
    );
    response.json({ revoked: true });
  });
