/**
 * Sentinel Predictive Routes
 * Provides predictions about policy violations
 */

import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { predictViolations, getMostLikelyViolation } from '@4runr/sentinel';
import { requireAuth } from '../middleware/auth.js';
import { readRateLimit, writeRateLimit } from '../middleware/rateLimit.js';

/**
 * Register Sentinel predictive routes
 */
export async function sentinelPredictiveRoutes(fastify: FastifyInstance) {
  /**
   * POST /api/sentinel/predict
   * Predict if a run will violate policies
   * Accepts either { runId: string } or { runState: RunState }
   */
  fastify.post(
    '/api/sentinel/predict',
    {
      preHandler: [requireAuth, writeRateLimit],
    },
    async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const { runId, runState: providedRunState } = (request.body || {}) as {
        runId?: string;
        runState?: unknown;
      };
      
      let runState: unknown;
      
      // Get Sentinel instance
      const { Sentinel } = await import('@4runr/sentinel');
      const sentinel = Sentinel.getInstance();
      const config = sentinel.getConfig();
      
      // If runState is provided, use it directly
      if (providedRunState) {
        runState = providedRunState;
      } else if (runId) {
        // Otherwise, get runState from Sentinel
        runState = sentinel.getRunStatus(runId);
        
        if (!runState) {
          return reply.status(404).send({
            error: 'Run not found or not being watched'
          });
        }
      } else {
        return reply.status(400).send({
          error: 'Either runId or runState is required'
        });
      }

      const predictions = predictViolations(runState as Parameters<typeof predictViolations>[0], config);
      const mostLikely = getMostLikelyViolation(runState as Parameters<typeof getMostLikelyViolation>[0], config);

      return {
        success: true,
        runId: (runState as { runId?: string }).runId || runId,
        predictions,
        mostLikelyViolation: mostLikely,
        willViolate: predictions.some(p => p.willViolate),
        summary: {
          totalPredictions: predictions.length,
          violationsPredicted: predictions.filter(p => p.willViolate).length,
          soonestViolation: mostLikely ? {
            policy: mostLikely.policy,
            estimatedTime: mostLikely.estimatedTime,
            confidence: mostLikely.confidence
          } : null
        }
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'Failed to predict violations',
        details: error.message
      });
    }
  }
  );

  /**
   * GET /api/sentinel/predict/:runId
   * Get predictions for a specific run
   */
  fastify.get(
    '/api/sentinel/predict/:runId',
    {
      preHandler: [requireAuth, readRateLimit],
    },
    async (request: FastifyRequest, reply: FastifyReply) => {
    try {
      const { runId } = request.params as { runId: string };

      const { Sentinel } = await import('@4runr/sentinel');
      const sentinel = Sentinel.getInstance();
      const config = sentinel.getConfig();
      
      const runState = sentinel.getRunStatus(runId);
      
      if (!runState) {
        return reply.status(404).send({
          error: 'Run not found or not being watched'
        });
      }

      const predictions = predictViolations(runState as Parameters<typeof predictViolations>[0], config);
      const mostLikely = getMostLikelyViolation(runState as Parameters<typeof getMostLikelyViolation>[0], config);

      return {
        success: true,
        runId,
        predictions,
        mostLikelyViolation: mostLikely,
        willViolate: predictions.some(p => p.willViolate)
      };
    } catch (error: any) {
      return reply.status(500).send({
        error: 'Failed to get predictions',
        details: error.message
      });
    }
  }
  );
}

