/**
 * Reviewer Console
 * Role-based console for adjudicating eResidency applications
 */

import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { authenticateJWT, requireRole } from '@the-order/shared';
import { ApplicationStatus } from '@the-order/schemas';
import { getReviewQueue, getEResidencyApplicationById, updateEResidencyApplication } from '@the-order/database';
import { logCredentialAction } from '@the-order/database';

export interface ReviewerConsoleConfig {
  // Configuration for reviewer console
}

/**
 * Register reviewer console routes
 */
export async function registerReviewerConsoleRoutes(
  server: FastifyInstance,
  _config?: ReviewerConsoleConfig
): Promise<void> {
  // Get review queue
  server.get(
    '/reviewer/queue',
    {
      preHandler: [authenticateJWT, requireRole('admin', 'reviewer', 'registrar')],
      schema: {
        querystring: {
          type: 'object',
          properties: {
            riskBand: { type: 'string', enum: ['low', 'medium', 'high'] },
            status: { type: 'string', enum: Object.values(ApplicationStatus) },
            limit: { type: 'number' },
            offset: { type: 'number' },
          },
        },
        description: 'Get review queue',
        tags: ['reviewer'],
      },
    },
      async (request: FastifyRequest, reply: FastifyReply) => {
      const { riskBand, status, limit, offset } = request.query as {
        riskBand?: string;
        status?: ApplicationStatus;
        limit?: number;
        offset?: number;
      };

      try {
        const { applications, total } = await getReviewQueue({
          riskBand: riskBand as 'low' | 'medium' | 'high' | undefined,
          status: status as ApplicationStatus | undefined,
          limit,
          offset,
        });

        return reply.send({
          applications,
          total,
          page: Math.floor((offset || 0) / (limit || 50)) + 1,
          pageSize: limit || 50,
        });
      } catch (error) {
        return reply.code(500).send({
          error: 'Failed to get review queue',
          message: error instanceof Error ? error.message : String(error),
        });
      }
    }
  );

  // Get application details
  server.get(
    '/reviewer/application/:applicationId',
    {
      preHandler: [authenticateJWT, requireRole('admin', 'reviewer', 'registrar')],
      schema: {
        params: {
          type: 'object',
          required: ['applicationId'],
          properties: {
            applicationId: { type: 'string' },
          },
        },
        description: 'Get application details',
        tags: ['reviewer'],
      },
    },
      async (request: FastifyRequest, reply: FastifyReply) => {
      const { applicationId } = request.params as { applicationId: string };

      try {
        const application = await getEResidencyApplicationById(applicationId);
        if (!application) {
          return reply.code(404).send({
            error: 'Application not found',
          });
        }

        return reply.send({
          application,
        });
      } catch (error) {
        return reply.code(500).send({
          error: 'Failed to get application',
          message: error instanceof Error ? error.message : String(error),
        });
      }
    }
  );

  // Review application
  server.post(
    '/reviewer/application/:applicationId/review',
    {
      preHandler: [authenticateJWT, requireRole('admin', 'reviewer', 'registrar')],
      schema: {
        params: {
          type: 'object',
          required: ['applicationId'],
          properties: {
            applicationId: { type: 'string' },
          },
        },
        body: {
          type: 'object',
          required: ['decision', 'justification'],
          properties: {
            decision: { type: 'string', enum: ['approve', 'reject', 'request_info'] },
            justification: { type: 'string' },
            requestedInfo: { type: 'array', items: { type: 'string' } },
          },
        },
        description: 'Review application',
        tags: ['reviewer'],
      },
    },
      async (request: FastifyRequest, reply: FastifyReply) => {
      const { applicationId } = request.params as { applicationId: string };
      const body = request.body as {
        decision: 'approve' | 'reject' | 'request_info';
        justification: string;
        requestedInfo?: string[];
      };
      const user = (request as any).user;

      try {
        const application = await getEResidencyApplicationById(applicationId);
        if (!application) {
          return reply.code(404).send({
            error: 'Application not found',
          });
        }

        // Update application status
        const status =
          body.decision === 'approve'
            ? ApplicationStatus.APPROVED
            : body.decision === 'reject'
              ? ApplicationStatus.REJECTED
              : ApplicationStatus.UNDER_REVIEW;

        await updateEResidencyApplication(applicationId, {
          status,
          reviewedAt: new Date().toISOString(),
          reviewedBy: user.id || user.sub || undefined,
          rejectionReason: body.decision === 'reject' ? body.justification : undefined,
        });

        // Log audit action (using 'verified' as the action type for application review)
        await logCredentialAction({
          credential_id: applicationId,
          issuer_did: 'system',
          subject_did: application.applicantDid || application.email,
          credential_type: ['ApplicationReview'],
          action: 'verified', // Using 'verified' as the action type since 'approved'/'rejected'/'reviewed' are not supported
          performed_by: user.id || user.sub || undefined,
          metadata: {
            justification: body.justification,
            requestedInfo: body.requestedInfo,
            decision: body.decision, // Store the actual decision in metadata
          },
        });

        // If approved, trigger issuance
        if (body.decision === 'approve') {
          // TODO: Trigger credential issuance
          // await triggerIssuance(applicationId);
        }

        return reply.send({
          applicationId,
          decision: body.decision,
          reviewedAt: new Date().toISOString(),
          reviewedBy: user.id || user.sub,
        });
      } catch (error) {
        return reply.code(500).send({
          error: 'Failed to review application',
          message: error instanceof Error ? error.message : String(error),
        });
      }
    }
  );

  // Bulk actions
  server.post(
    '/reviewer/bulk',
    {
      preHandler: [authenticateJWT, requireRole('admin', 'reviewer', 'registrar')],
      schema: {
        body: {
          type: 'object',
          required: ['action', 'applicationIds'],
          properties: {
            action: { type: 'string', enum: ['approve', 'reject', 'assign'] },
            applicationIds: { type: 'array', items: { type: 'string' } },
            justification: { type: 'string' },
            assignTo: { type: 'string' },
          },
        },
        description: 'Bulk actions on applications',
        tags: ['reviewer'],
      },
    },
      async (request: FastifyRequest, reply: FastifyReply) => {
      const body = request.body as {
        action: 'approve' | 'reject' | 'assign';
        applicationIds: string[];
        justification?: string;
        assignTo?: string;
      };
      const user = (request as any).user;

      try {
        // TODO: Perform bulk action
        // await performBulkAction(body);

        return reply.send({
          action: body.action,
          processed: body.applicationIds.length,
          processedAt: new Date().toISOString(),
          processedBy: user.id || user.sub,
        });
      } catch (error) {
        return reply.code(500).send({
          error: 'Failed to perform bulk action',
          message: error instanceof Error ? error.message : String(error),
        });
      }
    }
  );

  // Metrics dashboard
  server.get(
    '/reviewer/metrics',
    {
      preHandler: [authenticateJWT, requireRole('admin', 'reviewer', 'registrar')],
      schema: {
        querystring: {
          type: 'object',
          properties: {
            startDate: { type: 'string', format: 'date-time' },
            endDate: { type: 'string', format: 'date-time' },
          },
        },
        description: 'Get reviewer metrics',
        tags: ['reviewer'],
      },
    },
      async (request: FastifyRequest, reply: FastifyReply) => {
      const { startDate: _startDate, endDate: _endDate } = request.query as {
        startDate?: string;
        endDate?: string;
      };

      try {
        // TODO: Get metrics from database
        // const metrics = await getReviewerMetrics(startDate, endDate);

        return reply.send({
          medianDecisionTime: 0,
          approvalRate: 0,
          rejectionRate: 0,
          falseRejectRate: 0,
          totalReviewed: 0,
          averageRiskScore: 0,
        });
      } catch (error) {
        return reply.code(500).send({
          error: 'Failed to get metrics',
          message: error instanceof Error ? error.message : String(error),
        });
      }
    }
  );

  // Appeals intake
  server.post(
    '/reviewer/appeals',
    {
      preHandler: [authenticateJWT],
      schema: {
        body: {
          type: 'object',
          required: ['applicationId', 'reason'],
          properties: {
            applicationId: { type: 'string' },
            reason: { type: 'string' },
            evidence: { type: 'array', items: { type: 'object' } },
          },
        },
        description: 'Submit appeal',
        tags: ['reviewer'],
      },
    },
      async (request: FastifyRequest, reply: FastifyReply) => {
      const body = request.body as {
        applicationId: string;
        reason: string;
        evidence?: unknown[];
      };

      try {
        // TODO: Create appeal
        // const appeal = await createAppeal(body);

        return reply.send({
          appealId: 'appeal-id',
          applicationId: body.applicationId,
          status: 'submitted',
          submittedAt: new Date().toISOString(),
        });
      } catch (error) {
        return reply.code(500).send({
          error: 'Failed to submit appeal',
          message: error instanceof Error ? error.message : String(error),
        });
      }
    }
  );
}

