import { Response } from 'express';
import { prisma } from '../config/database';
import { AuthRequest, ApproverAuthRequest, VisitorCheckpointAuthRequest } from '../middleware/auth';

// Register the current device with the signed-in user. Mobile app calls
// this on launch after the user grants push permission and Capacitor's
// PushNotifications plugin produces a token. Upserts on `token` so the
// same device re-registering doesn't pile up duplicate rows.
//
// Checkpoint users: the visitorCheckpointId is stored in the `approverId`
// column (no schema change needed — checkpoint CUIDs are globally unique
// and never collide with real Approver CUIDs).
function pickPrincipal(req: any): { ownerId: string; adminId: string | null; approverId: string | null } {
  // Checkpoint JWT carries visitorCheckpointId. Store its ID in approverId
  // so no additional column is needed on DeviceToken.
  if (req.visitorCheckpointId) return { ownerId: req.ownerId, adminId: null, approverId: req.visitorCheckpointId };
  if (req.approverId)          return { ownerId: req.ownerId, adminId: null, approverId: req.approverId };
  if (req.adminId)             return { ownerId: req.ownerId, adminId: req.adminId, approverId: null };
  return { ownerId: req.ownerId, adminId: null, approverId: null };
}

export async function registerDevice(
  req: AuthRequest | ApproverAuthRequest | VisitorCheckpointAuthRequest,
  res: Response,
): Promise<void> {
  try {
    const { token, platform } = req.body as { token?: string; platform?: string };
    if (!token || typeof token !== 'string') { res.status(400).json({ error: 'token is required' }); return; }
    if (!platform || !['ios', 'android', 'web'].includes(platform)) { res.status(400).json({ error: 'platform must be ios | android | web' }); return; }

    const principal = pickPrincipal(req);
    if (!principal.ownerId) { res.status(401).json({ error: 'Unauthorized' }); return; }

    // Find an existing registration for this principal so we update in place
    // rather than accumulating new rows on every token refresh.
    let existingForUser = null;
    if (principal.adminId) {
      existingForUser = await prisma.deviceToken.findFirst({ where: { adminId: principal.adminId } });
    } else if (principal.approverId) {
      // This branch handles both real approvers and checkpoint users (whose
      // checkpointId is stored in approverId).
      existingForUser = await prisma.deviceToken.findFirst({ where: { approverId: principal.approverId } });
    }

    let row;
    if (existingForUser) {
      // Remove any other row that already holds this token (e.g. prior user on same device).
      await prisma.deviceToken.deleteMany({ where: { token, NOT: { id: existingForUser.id } } });
      row = await prisma.deviceToken.update({
        where: { id: existingForUser.id },
        data: { token, platform },
      });
    } else {
      // No prior registration for this principal — upsert on token to re-bind if the
      // device is switching users.
      row = await prisma.deviceToken.upsert({
        where: { token },
        create: {
          token,
          platform,
          ownerId: principal.ownerId,
          adminId: principal.adminId,
          approverId: principal.approverId,
        },
        update: {
          platform,
          ownerId: principal.ownerId,
          adminId: principal.adminId,
          approverId: principal.approverId,
        },
      });
    }
    res.status(201).json({ id: row.id });
  } catch (e) {
    console.error('registerDevice', e);
    res.status(500).json({ error: 'Failed to register device' });
  }
}

export async function unregisterDevice(
  req: AuthRequest | ApproverAuthRequest | VisitorCheckpointAuthRequest,
  res: Response,
): Promise<void> {
  try {
    const { token } = req.body as { token?: string };
    if (!token) { res.status(400).json({ error: 'token is required' }); return; }
    await prisma.deviceToken.deleteMany({ where: { token } });
    res.json({ ok: true });
  } catch (e) {
    console.error('unregisterDevice', e);
    res.status(500).json({ error: 'Failed to unregister device' });
  }
}
