/* eslint-disable @typescript-eslint/no-unused-vars */
/**
 * Predictive Analytics Routes - REST API endpoints
 * [2.2] Real-time scoring API
 * [4.3] CS team dashboard backend
 * [5] Admin API routes
 */

import type { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify';
import { z } from 'zod';
import { UnauthorizedError, ForbiddenError } from '../../lib/errors.js';
import { extractFeaturesFromTelemetry } from './feature-extractor.js';
import { featureStore } from './feature-store.js';
import { churnModel } from './churn-model.js';
import { healthScoringEngine } from './health-scoring.js';
import { campaignEngine } from './campaign-engine.js';
import { predictiveAnalyticsRepo } from './repository.js';
import {
  ChurnScoreRequestSchema,
  ChurnBatchRequestSchema,
  AtRiskUsersQuerySchema,
  CreateCampaignSchema,
  CampaignTriggerSchema,
  RiskSegmentEnum,
  type UserChurnPredictionDoc,
} from './types.js';

// Auth Helpers
interface JwtPayload {
  sub: string;
  role?: string;
}

function requireAuth(req: { jwtPayload?: JwtPayload }): string {
  if (!req.jwtPayload?.sub) throw new UnauthorizedError('Authentication required');
  return req.jwtPayload.sub;
}

function requireAdmin(req: { jwtPayload?: JwtPayload }): void {
  requireAuth(req);
  if (req.jwtPayload?.role !== 'admin') throw new ForbiddenError('Admin access required');
}

// Get telemetry repository for fetching user events
async function getUserTelemetryEvents(
  userId: string,
  productId: string,
  days: number = 30
): Promise<Array<Record<string, unknown>>> {
  const { getRegisteredContainer } = await import('@bytelyst/cosmos');
  const container = getRegisteredContainer('telemetry_events');

  const cutoff = new Date();
  cutoff.setDate(cutoff.getDate() - days);

  const pk = `${productId}:${cutoff.getFullYear()}${String(cutoff.getMonth() + 1).padStart(2, '0')}`;

  const query = {
    query: 'SELECT * FROM c WHERE c.pk = @pk AND c.userId = @userId ORDER BY c.occurredAt DESC',
    parameters: [
      { name: '@pk', value: pk },
      { name: '@userId', value: userId },
    ],
  };

  const { resources } = await container.items.query(query).fetchAll();
  return resources as Array<Record<string, unknown>>;
}

export async function predictiveAnalyticsRoutes(fastify: FastifyInstance): Promise<void> {
  // ==================== Churn Prediction Routes ====================

  // POST /predictive/churn-score - Single user prediction
  fastify.post('/predictive/churn-score', {
    preHandler: [requireAuth],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const body = ChurnScoreRequestSchema.parse(request.body);
      const { userId, productId, horizon } = body;

      request.log.info({ userId, productId }, 'Churn score request');

      // Get cached prediction if fresh (< 24h)
      const cached = await predictiveAnalyticsRepo.getChurnPrediction(
        userId,
        productId,
        parseInt(horizon, 10)
      );

      if (cached) {
        const age = Date.now() - new Date(cached.predictionTimestamp).getTime();
        if (age < 24 * 60 * 60 * 1000) {
          return reply.send({
            userId: cached.userId,
            churnProbability: cached.churnProbability,
            riskSegment: cached.riskSegment,
            confidenceScore: cached.confidenceScore,
            explanation: cached.explanation,
            modelVersion: cached.modelVersion,
            cached: true,
          });
        }
      }

      // Fetch telemetry events
      const rawEvents = await getUserTelemetryEvents(userId, productId);
      const events = rawEvents as unknown as Parameters<typeof extractFeaturesFromTelemetry>[2];

      // Extract features
      const features = extractFeaturesFromTelemetry(
        userId,
        productId,
        events as Parameters<typeof extractFeaturesFromTelemetry>[2],
        new Date()
      );

      // Store features
      await featureStore.saveFeatureVector(userId, productId, features);

      // Run prediction
      const prediction = churnModel.predict(features, parseInt(horizon, 10));

      // Save prediction (construct doc carefully to avoid duplicate property issues)
      const { userId: _uid, productId: _pid, ...predictionData } = prediction;
      const doc: UserChurnPredictionDoc = {
        id: `cp_${crypto.randomUUID()}`,
        pk: `${userId}:${productId}`,
        userId,
        productId,
        ...predictionData,
        explanation: prediction.explanation,
        interventionHistory: [],
        createdAt: new Date().toISOString(),
        ttl: (parseInt(horizon, 10) + 90) * 24 * 60 * 60,
      };

      await predictiveAnalyticsRepo.saveChurnPrediction(doc);

      return reply.send({
        userId,
        churnProbability: prediction.churnProbability,
        riskSegment: prediction.riskSegment,
        confidenceScore: prediction.confidenceScore,
        explanation: prediction.explanation,
        modelVersion: prediction.modelVersion,
        cached: false,
      });
    },
  });

  // POST /predictive/churn-batch - Batch scoring
  fastify.post('/predictive/churn-batch', {
    preHandler: [requireAuth],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const body = ChurnBatchRequestSchema.parse(request.body);
      const { userIds, productId, horizon } = body;

      request.log.info({ userCount: userIds.length, productId }, 'Batch churn score request');

      const results = await Promise.all(
        userIds.map(async userId => {
          const rawEvents = await getUserTelemetryEvents(userId, productId);
          const events = rawEvents as unknown as Parameters<typeof extractFeaturesFromTelemetry>[2];
          const features = extractFeaturesFromTelemetry(userId, productId, events, new Date());
          const prediction = churnModel.predict(features, parseInt(horizon, 10));
          return {
            userId,
            churnProbability: prediction.churnProbability,
            riskSegment: prediction.riskSegment,
          };
        })
      );

      return reply.send({
        productId,
        horizon: parseInt(horizon, 10),
        results,
        summary: {
          total: results.length,
          critical: results.filter(r => r.riskSegment === 'critical').length,
          high: results.filter(r => r.riskSegment === 'high').length,
          medium: results.filter(r => r.riskSegment === 'medium').length,
          low: results.filter(r => r.riskSegment === 'low').length,
        },
      });
    },
  });

  // GET /predictive/at-risk-users - List at-risk users
  fastify.get('/predictive/at-risk-users', {
    preHandler: [requireAuth],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const query = AtRiskUsersQuerySchema.parse(request.query);
      const { productId, segment, limit, offset } = query;

      const predictions = await predictiveAnalyticsRepo.getAtRiskUsers(
        productId || '',
        segment,
        limit,
        offset
      );

      return reply.send({
        users: predictions.map(p => ({
          userId: p.userId,
          productId: p.productId,
          churnProbability: p.churnProbability,
          riskSegment: p.riskSegment,
          confidenceScore: p.confidenceScore,
          predictionTimestamp: p.predictionTimestamp,
          topRiskFactors: p.explanation?.topRiskFactors?.slice(0, 3) || [],
        })),
        pagination: {
          limit,
          offset,
          total: predictions.length, // Simplified - should use count query
        },
      });
    },
  });

  // GET /predictive/users/:id/risk-profile - User risk profile
  fastify.get('/predictive/users/:id/risk-profile', {
    preHandler: [requireAuth],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const { id } = request.params as { id: string };
      const { productId } = request.query as { productId?: string };

      if (!productId) {
        return reply.status(400).send({ error: 'productId query parameter required' });
      }

      const predictions = await predictiveAnalyticsRepo.getUserRiskProfile(id, productId);
      const latest = predictions[0];

      if (!latest) {
        return reply.status(404).send({ error: 'No predictions found for user' });
      }

      return reply.send({
        userId: id,
        productId,
        currentRisk: {
          churnProbability: latest.churnProbability,
          riskSegment: latest.riskSegment,
          confidenceScore: latest.confidenceScore,
          predictionTimestamp: latest.predictionTimestamp,
        },
        history: predictions.map(p => ({
          timestamp: p.predictionTimestamp,
          churnProbability: p.churnProbability,
          riskSegment: p.riskSegment,
        })),
        explanation: latest.explanation,
        suggestedActions: latest.explanation?.suggestedActions || [],
      });
    },
  });

  // ==================== Health Score Routes ====================

  // GET /predictive/health - All products health
  fastify.get('/predictive/health', {
    preHandler: [requireAdmin],
    handler: async (_request: FastifyRequest, reply: FastifyReply) => {
      const scores = await predictiveAnalyticsRepo.getAllProductHealthScores();

      return reply.send({
        scores: scores.map(s => ({
          productId: s.productId,
          date: s.date,
          overallHealthScore: s.overallHealthScore,
          healthStatus: s.healthStatus,
          dimensions: s.dimensions,
          anomalies: s.anomalies.slice(0, 3),
          forecasts: s.forecasts,
        })),
      });
    },
  });

  // GET /predictive/health/:productId - Product health detail
  fastify.get('/predictive/health/:productId', {
    preHandler: [requireAuth],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const { productId } = request.params as { productId: string };
      const today = new Date().toISOString().split('T')[0];

      const score = await predictiveAnalyticsRepo.getHealthScore(productId, today);

      if (!score) {
        return reply.status(404).send({ error: 'Health score not found' });
      }

      return reply.send(score);
    },
  });

  // GET /predictive/health/:productId/trends - Health trends
  fastify.get('/predictive/health/:productId/trends', {
    preHandler: [requireAuth],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const { productId } = request.params as { productId: string };
      const { days = '30' } = request.query as { days?: string };

      const history = await predictiveAnalyticsRepo.getHealthHistory(productId, parseInt(days, 10));

      return reply.send({
        productId,
        days: parseInt(days, 10),
        trends: history.map(h => ({
          date: h.date,
          overallHealthScore: h.overallHealthScore,
          healthStatus: h.healthStatus,
          dimensions: {
            acquisition: h.dimensions.acquisition.score,
            activation: h.dimensions.activation.score,
            retention: h.dimensions.retention.score,
            engagement: h.dimensions.engagement.score,
            revenue: h.dimensions.revenue.score,
            stability: h.dimensions.stability.score,
          },
        })),
      });
    },
  });

  // ==================== Model Performance Routes ====================

  // GET /predictive/model/performance - Model metrics
  fastify.get('/predictive/model/performance', {
    preHandler: [requireAdmin],
    handler: async (_request: FastifyRequest, reply: FastifyReply) => {
      const latest = await predictiveAnalyticsRepo.getLatestModelPerformance();
      const history = await predictiveAnalyticsRepo.getModelPerformanceHistory(5);

      return reply.send({
        current: latest,
        history: history.map(h => ({
          modelVersion: h.metrics.modelVersion,
          modelType: h.metrics.modelType,
          trainedAt: h.metrics.trainedAt,
          auc: h.metrics.auc,
          precisionAt10: h.metrics.precisionAt10,
          recallAt10: h.metrics.recallAt10,
          calibrationSlope: h.metrics.calibrationSlope,
        })),
      });
    },
  });

  // GET /predictive/model/features - Feature importance
  fastify.get('/predictive/model/features', {
    preHandler: [requireAdmin],
    handler: async (_request: FastifyRequest, reply: FastifyReply) => {
      const latest = await predictiveAnalyticsRepo.getLatestModelPerformance();

      return reply.send({
        modelVersion: latest?.metrics.modelVersion || '1.0.0',
        featureImportance: latest?.metrics.featureImportance || [],
      });
    },
  });

  // ==================== Campaign Routes ====================

  // GET /predictive/campaigns - List campaigns
  fastify.get('/predictive/campaigns', {
    preHandler: [requireAdmin],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const { productId, status } = request.query as {
        productId?: string;
        status?: string;
      };

      const campaigns = await predictiveAnalyticsRepo.listCampaigns(productId, status);

      return reply.send({
        campaigns: campaigns.map(c => ({
          id: c.id,
          name: c.name,
          description: c.description,
          productId: c.productId,
          status: c.status,
          trigger: c.trigger,
          audience: c.audience,
          stats: c.stats,
          createdAt: c.createdAt,
        })),
      });
    },
  });

  // POST /predictive/campaigns - Create campaign
  fastify.post('/predictive/campaigns', {
    preHandler: [requireAdmin],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const body = CreateCampaignSchema.parse(request.body);

      const campaign = await campaignEngine.createCampaign(body);

      return reply.status(201).send({
        id: campaign.id,
        name: campaign.name,
        status: campaign.status,
        createdAt: campaign.createdAt,
      });
    },
  });

  // PATCH /predictive/campaigns/:id - Update campaign
  fastify.patch('/predictive/campaigns/:id', {
    preHandler: [requireAdmin],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const { id } = request.params as { id: string };
      const updates = request.body as Partial<{
        status: 'active' | 'paused' | 'completed';
        name: string;
        description: string;
      }>;

      if (updates.status === 'active') {
        const campaign = await campaignEngine.activateCampaign(id);
        return reply.send({ success: true, campaign });
      }

      const updated = await predictiveAnalyticsRepo.updateCampaign(id, updates);

      if (!updated) {
        return reply.status(404).send({ error: 'Campaign not found' });
      }

      return reply.send({ success: true, campaign: updated });
    },
  });

  // GET /predictive/campaigns/:id/stats - Campaign stats
  fastify.get('/predictive/campaigns/:id/stats', {
    preHandler: [requireAdmin],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const { id } = request.params as { id: string };

      const stats = await campaignEngine.getCampaignStats(id);

      if (!stats) {
        return reply.status(404).send({ error: 'Campaign not found' });
      }

      return reply.send(stats);
    },
  });

  // POST /predictive/campaigns/:id/trigger - Manual trigger
  fastify.post('/predictive/campaigns/:id/trigger', {
    preHandler: [requireAdmin],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const { id } = request.params as { id: string };
      const body = CampaignTriggerSchema.parse(request.body);

      const results = await campaignEngine.manualTrigger(id, body.testUserId || 'test_user');

      return reply.send({
        success: true,
        testMode: true,
        results,
      });
    },
  });

  // DELETE /predictive/campaigns/:id - Delete campaign
  fastify.delete('/predictive/campaigns/:id', {
    preHandler: [requireAdmin],
    handler: async (request: FastifyRequest, reply: FastifyReply) => {
      const { id } = request.params as { id: string };

      const success = await predictiveAnalyticsRepo.deleteCampaign(id);

      if (!success) {
        return reply.status(404).send({ error: 'Campaign not found' });
      }

      return reply.send({ success: true });
    },
  });
}
