/**
 * Push MFA approval endpoints for SmartAuth Phase 5D.
 *
 * POST /auth/mfa/push/create      — create a push approval request (internal/service)
 * GET  /auth/mfa/push/pending      — list pending approvals for current user
 * POST /auth/mfa/push/:id/respond  — approve or deny a push approval
 * GET  /auth/mfa/push/:id/status   — poll approval status (for requesting client)
 */

import type { FastifyInstance } from 'fastify';
import { BadRequestError, UnauthorizedError, NotFoundError } from '../../../lib/errors.js';
import * as repo from './repository.js';
import { PushApprovalRespondSchema, PushApprovalCreateSchema } from './types.js';

export async function pushApprovalRoutes(app: FastifyInstance) {
  // ── Create push approval (called by login flow when push MFA is triggered) ──

  app.post('/auth/mfa/push/create', async req => {
    const payload = req.jwtPayload;
    // Allow service-to-service or admin calls
    if (!payload?.sub) throw new UnauthorizedError('Authentication required');
    if (!payload.role || !['super_admin', 'admin', 'service'].includes(payload.role)) {
      throw new UnauthorizedError('Service or admin access required');
    }

    const parsed = PushApprovalCreateSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const approval = repo.create({
      productId: 'smartauth',
      userId: parsed.data.userId,
      requestProductId: parsed.data.requestProductId,
      requestPlatform: parsed.data.requestPlatform,
      requestIp: parsed.data.requestIp,
      requestGeo: parsed.data.requestGeo,
      challengeToken: parsed.data.challengeToken,
    });

    req.log.info(
      { approvalId: approval.id, userId: parsed.data.userId },
      '[auth] Push approval created'
    );
    return { id: approval.id, expiresAt: approval.expiresAt };
  });

  // ── List pending approvals for current user ─────────────────

  app.get('/auth/mfa/push/pending', async req => {
    const payload = req.jwtPayload;
    if (!payload?.sub) throw new UnauthorizedError('Authentication required');

    const pending = repo.getPendingByUserId(payload.sub);
    return pending.map(a => ({
      id: a.id,
      requestProductId: a.requestProductId,
      requestPlatform: a.requestPlatform,
      requestIp: a.requestIp,
      requestGeo: a.requestGeo,
      createdAt: a.createdAt,
      expiresAt: a.expiresAt,
    }));
  });

  // ── Respond to a push approval ─────────────────────────────

  app.post('/auth/mfa/push/:id/respond', async req => {
    const payload = req.jwtPayload;
    if (!payload?.sub) throw new UnauthorizedError('Authentication required');

    const { id } = req.params as { id: string };
    const parsed = PushApprovalRespondSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const approval = repo.getById(id);
    if (!approval) throw new NotFoundError('Approval not found');
    if (approval.userId !== payload.sub) throw new UnauthorizedError('Not your approval');
    if (approval.status !== 'pending') {
      throw new BadRequestError(`Approval already ${approval.status}`);
    }

    const action = parsed.data.action === 'approve' ? ('approved' as const) : ('denied' as const);
    const updated = repo.respond(id, action);
    if (!updated) throw new BadRequestError('Failed to respond to approval');

    req.log.info({ approvalId: id, action, userId: payload.sub }, '[auth] Push approval responded');
    return { id: updated.id, status: updated.status, respondedAt: updated.respondedAt };
  });

  // ── Poll approval status (for the requesting login client) ──

  app.get('/auth/mfa/push/:id/status', async req => {
    const { id } = req.params as { id: string };
    const approval = repo.getById(id);
    if (!approval) throw new NotFoundError('Approval not found');

    return {
      id: approval.id,
      status: approval.status,
      respondedAt: approval.respondedAt ?? null,
    };
  });
}
