import { Router, type Response } from 'express';
import { z } from 'zod';
import { requireAdmin, requireAuth, type AuthenticatedRequest } from './auth';
import { pool } from './db';
import { recordPairEvent } from './relationshipEvents';
import { notifyUsers } from './notifications';

export const profilePhotosRouter = Router();

const imageSchema = z.string().max(1_700_000).regex(/^data:image\/(jpeg|webp);base64,/);
const uploadSchema = z.object({ original: imageSchema, blurred: imageSchema });

const decodeImage = (value: string): { data: Buffer; mime: string } => {
  const match = /^data:(image\/(?:jpeg|webp));base64,(.+)$/.exec(value);
  if (!match) throw new Error('Invalid image payload');
  return { mime: match[1], data: Buffer.from(match[2], 'base64') };
};

const acceptedPair = async (first: string, second: string): Promise<boolean> => {
  const result = await pool.query(
    `SELECT 1 FROM engagement_requests WHERE status='accepted' AND
      ((sender_user_id=$1 AND recipient_user_id=$2) OR
       (sender_user_id=$2 AND recipient_user_id=$1)) LIMIT 1`,
    [first, second],
  );
  return Boolean(result.rowCount);
};

const acceptedRequestId = async (first: string, second: string): Promise<string | undefined> => {
  const result = await pool.query<{ id: string }>(
    `SELECT id FROM engagement_requests WHERE status='accepted' AND
      ((sender_user_id=$1 AND recipient_user_id=$2) OR
       (sender_user_id=$2 AND recipient_user_id=$1)) ORDER BY updated_at DESC LIMIT 1`,
    [first, second],
  );
  return result.rows[0]?.id;
};

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

profilePhotosRouter.get('/admin/users/:viewerId/photo/:ownerId', requireAuth, requireAdmin,
  async (request, response) => {
    const viewer = z.uuid().safeParse(request.params.viewerId);
    const owner = z.uuid().safeParse(request.params.ownerId);
    if (!viewer.success || !owner.success) {
      response.status(400).json({ error: 'Invalid profile ID' }); return;
    }
    const result = await pool.query<{
      original_data: Buffer; original_mime: string; blurred_data: Buffer; blurred_mime: string;
      access_status: string | null;
    }>(
      `SELECT photo.*,access.status AS access_status FROM profile_photos photo
       LEFT JOIN profile_photo_access access ON access.owner_user_id=photo.user_id
         AND access.viewer_user_id=$2 WHERE photo.user_id=$1`,
      [owner.data, viewer.data],
    );
    const photo = result.rows[0];
    if (!photo) { response.status(404).json({ error: 'Profile photo not found' }); return; }
    const revealed = owner.data === viewer.data || photo.access_status === 'revealed';
    const data = revealed ? photo.original_data : photo.blurred_data;
    const mime = revealed ? photo.original_mime : photo.blurred_mime;
    response.json({ photo: { dataUrl: `data:${mime};base64,${data.toString('base64')}`,
      mode: revealed ? 'revealed' : 'blurred', accessStatus: photo.access_status } });
  });

profilePhotosRouter.put('/me/profile-photo', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const userId = requireCandidate(request, response);
    if (!userId) return;
    const parsed = uploadSchema.safeParse(request.body);
    if (!parsed.success) { response.status(400).json({ error: 'Invalid profile photo' }); return; }
    const original = decodeImage(parsed.data.original);
    const blurred = decodeImage(parsed.data.blurred);
    if (original.data.length > 1_200_000 || blurred.data.length > 250_000) {
      response.status(413).json({ error: 'Profile photo is too large' }); return;
    }
    await pool.query(
      `INSERT INTO profile_photos (user_id,original_data,original_mime,blurred_data,blurred_mime)
       VALUES ($1,$2,$3,$4,$5) ON CONFLICT (user_id) DO UPDATE SET
       original_data=EXCLUDED.original_data,original_mime=EXCLUDED.original_mime,
       blurred_data=EXCLUDED.blurred_data,blurred_mime=EXCLUDED.blurred_mime,updated_at=NOW()`,
      [userId, original.data, original.mime, blurred.data, blurred.mime],
    );
    response.json({ saved: true });
  });

profilePhotosRouter.delete('/me/profile-photo', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const userId = requireCandidate(request, response);
    if (!userId) return;
    await pool.query('DELETE FROM profile_photos WHERE user_id=$1', [userId]);
    response.json({ deleted: true });
  });

profilePhotosRouter.get('/profiles/:ownerId/photo', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const viewerId = requireCandidate(request, response);
    if (!viewerId) return;
    const ownerId = z.uuid().safeParse(request.params.ownerId);
    if (!ownerId.success) { response.status(400).json({ error: 'Invalid profile' }); return; }
    const ownPhoto = ownerId.data === viewerId;
    if (!ownPhoto && !(await acceptedPair(ownerId.data, viewerId))) {
      response.status(403).json({ error: 'Photo is available after accepting the introduction' }); return;
    }
    const result = await pool.query<{
      original_data: Buffer; original_mime: string; blurred_data: Buffer; blurred_mime: string;
      access_status: string | null;
    }>(
      `SELECT photo.*,access.status AS access_status FROM profile_photos photo
       LEFT JOIN profile_photo_access access ON access.owner_user_id=photo.user_id
         AND access.viewer_user_id=$2 WHERE photo.user_id=$1`,
      [ownerId.data, viewerId],
    );
    const photo = result.rows[0];
    if (!photo) { response.status(404).json({ error: 'Profile photo not found' }); return; }
    const revealed = ownPhoto || photo.access_status === 'revealed';
    const data = revealed ? photo.original_data : photo.blurred_data;
    const mime = revealed ? photo.original_mime : photo.blurred_mime;
    response.json({ photo: { dataUrl: `data:${mime};base64,${data.toString('base64')}`,
      mode: revealed ? 'revealed' : 'blurred', accessStatus: photo.access_status } });
  });

profilePhotosRouter.post('/profiles/:ownerId/photo-request', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const viewerId = requireCandidate(request, response);
    if (!viewerId) return;
    const owner = z.uuid().safeParse(request.params.ownerId);
    if (!owner.success || owner.data === viewerId) { response.status(400).json({ error: 'Invalid profile' }); return; }
    if (!(await acceptedPair(owner.data, viewerId))) {
      response.status(409).json({ error: 'An accepted introduction is required' }); return;
    }
    const result = await pool.query(
      `INSERT INTO profile_photo_access (owner_user_id,viewer_user_id,status,requested_by)
       SELECT $1,$2,'requested',$2 WHERE EXISTS (SELECT 1 FROM profile_photos WHERE user_id=$1)
       ON CONFLICT (owner_user_id,viewer_user_id) DO UPDATE SET
       status=CASE WHEN profile_photo_access.status='revealed' THEN 'revealed' ELSE 'requested' END,
       requested_by=$2,updated_at=NOW() RETURNING status`,
      [owner.data, viewerId],
    );
    if (!result.rowCount) { response.status(404).json({ error: 'Profile photo not found' }); return; }
    if (result.rows[0].status === 'requested') {
      await recordPairEvent(owner.data, viewerId, viewerId, 'photo_requested', {
        ownerUserId: owner.data, viewerUserId: viewerId,
      });
      await notifyUsers([owner.data], {
        type: 'photo_request', title: 'طلب رؤية الصورة',
        body: `${request.authUser!.displayName} يطلب رؤية صورتك الشخصية.`,
        requestId: await acceptedRequestId(owner.data, viewerId),
        dedupeKey: `photo-request:${owner.data}:${viewerId}:${Date.now()}`,
      });
    }
    response.json({ status: result.rows[0].status });
  });

profilePhotosRouter.get('/me/photo-requests', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const ownerId = requireCandidate(request, response);
    if (!ownerId) return;
    const result = await pool.query(
      `SELECT access.viewer_user_id AS "viewerUserId",profile.display_name AS "viewerName",
        access.status,access.updated_at AS "updatedAt"
       FROM profile_photo_access access JOIN profiles profile ON profile.user_id=access.viewer_user_id
       WHERE access.owner_user_id=$1 ORDER BY access.updated_at DESC`, [ownerId],
    );
    response.json({ requests: result.rows });
  });

profilePhotosRouter.patch('/me/photo-requests/:viewerId', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const ownerId = requireCandidate(request, response);
    if (!ownerId) return;
    const parsed = z.object({ decision: z.enum(['approved', 'declined']) }).safeParse(request.body);
    const viewer = z.uuid().safeParse(request.params.viewerId);
    if (!parsed.success || !viewer.success) { response.status(400).json({ error: 'Invalid decision' }); return; }
    const status = parsed.data.decision === 'approved' ? 'revealed' : 'declined';
    const result = await pool.query(
      `UPDATE profile_photo_access SET status=$1,updated_at=NOW()
       WHERE owner_user_id=$2 AND viewer_user_id=$3 AND status='requested' RETURNING status`,
      [status, ownerId, viewer.data],
    );
    if (!result.rowCount) { response.status(404).json({ error: 'Photo request not found' }); return; }
    await recordPairEvent(ownerId, viewer.data, ownerId,
      parsed.data.decision === 'approved' ? 'photo_approved' : 'photo_declined', {
        ownerUserId: ownerId, viewerUserId: viewer.data,
      });
    await notifyUsers([viewer.data], {
      type: 'photo_decision', title: parsed.data.decision === 'approved'
        ? 'تمت الموافقة على عرض الصورة' : 'تم الاعتذار عن عرض الصورة',
      body: parsed.data.decision === 'approved'
        ? `${request.authUser!.displayName} سمح لك برؤية الصورة الشخصية.`
        : `${request.authUser!.displayName} اعتذر عن عرض الصورة الشخصية.`,
      requestId: await acceptedRequestId(ownerId, viewer.data),
      dedupeKey: `photo-decision:${ownerId}:${viewer.data}:${status}:${Date.now()}`,
    });
    response.json({ status });
  });

profilePhotosRouter.post('/profiles/:viewerId/photo-reveal', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const ownerId = requireCandidate(request, response);
    if (!ownerId) return;
    const viewer = z.uuid().safeParse(request.params.viewerId);
    if (!viewer.success || viewer.data === ownerId || !(await acceptedPair(ownerId, viewer.data))) {
      response.status(409).json({ error: 'An accepted introduction is required' }); return;
    }
    const result = await pool.query(
      `INSERT INTO profile_photo_access (owner_user_id,viewer_user_id,status,requested_by)
       SELECT $1,$2,'revealed',$1 WHERE EXISTS (SELECT 1 FROM profile_photos WHERE user_id=$1)
       ON CONFLICT (owner_user_id,viewer_user_id) DO UPDATE SET status='revealed',
       requested_by=$1,updated_at=NOW() RETURNING status`, [ownerId, viewer.data],
    );
    if (!result.rowCount) { response.status(404).json({ error: 'Add a profile photo first' }); return; }
    await recordPairEvent(ownerId, viewer.data, ownerId, 'photo_shared', {
      ownerUserId: ownerId, viewerUserId: viewer.data,
    });
    await notifyUsers([viewer.data], {
      type: 'photo_decision', title: 'تمت مشاركة صورة معك',
      body: `${request.authUser!.displayName} أتاح لك رؤية الصورة الشخصية.`,
      requestId: await acceptedRequestId(ownerId, viewer.data),
      dedupeKey: `photo-shared:${ownerId}:${viewer.data}:${Date.now()}`,
    });
    response.json({ status: 'revealed' });
  });

profilePhotosRouter.get('/profiles/:viewerId/my-photo-sharing', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const ownerId = requireCandidate(request, response);
    if (!ownerId) return;
    const viewer = z.uuid().safeParse(request.params.viewerId);
    if (!viewer.success || viewer.data === ownerId || !(await acceptedPair(ownerId, viewer.data))) {
      response.status(409).json({ error: 'An accepted introduction is required' }); return;
    }
    const result = await pool.query<{ has_photo: boolean; status: string | null }>(
      `SELECT EXISTS (SELECT 1 FROM profile_photos WHERE user_id=$1) AS has_photo,
        (SELECT status FROM profile_photo_access
         WHERE owner_user_id=$1 AND viewer_user_id=$2) AS status`,
      [ownerId, viewer.data],
    );
    response.json({ sharing: {
      hasPhoto: result.rows[0]?.has_photo ?? false,
      status: result.rows[0]?.status ?? null,
    } });
  });

profilePhotosRouter.post('/profiles/:viewerId/photo-hide', requireAuth,
  async (request: AuthenticatedRequest, response) => {
    const ownerId = requireCandidate(request, response);
    if (!ownerId) return;
    const viewer = z.uuid().safeParse(request.params.viewerId);
    if (!viewer.success || viewer.data === ownerId || !(await acceptedPair(ownerId, viewer.data))) {
      response.status(409).json({ error: 'An accepted introduction is required' }); return;
    }
    const removed = await pool.query(
      `DELETE FROM profile_photo_access
       WHERE owner_user_id=$1 AND viewer_user_id=$2 AND status='revealed'
       RETURNING owner_user_id`,
      [ownerId, viewer.data],
    );
    if (removed.rowCount) {
      await recordPairEvent(ownerId, viewer.data, ownerId, 'photo_hidden', {
        ownerUserId: ownerId, viewerUserId: viewer.data,
      });
    }
    response.json({ hidden: true });
  });
