import { Request, Response } from 'express';
import { z } from 'zod';

import { getPrismaClient } from '../../../config/database.config';
import { NotFoundError } from '../../../errors/http-error';
import { getErrorMessage } from '../../../utils/error-utils';
import { CalculateRiskScoreDto, RiskFiltersDto } from '../governance.dto';

import { riskService } from './risk.service';

/**
 * EN: Risk Management Controller
 * VI: Controller quản lý rủi ro
 */
export class RiskController {
  private prisma = getPrismaClient();
  /**
   * EN: List risk scores
   * VI: Liệt kê các điểm rủi ro
   */
  async list(req: Request, res: Response): Promise<void> {
    try {
      const filters = RiskFiltersDto.parse({
        minScore: req.query.minScore ? parseInt(req.query.minScore as string) : undefined,
        maxScore: req.query.maxScore ? parseInt(req.query.maxScore as string) : undefined,
        level: req.query.level as any,
        userId: req.query.userId as string,
        skip: parseInt(req.query.skip as string) || 0,
        take: parseInt(req.query.take as string) || 20,
      });

      const result = await riskService.getRiskScores(filters);

      res.json({
        success: true,
        data: {
          scores: result.scores,
          pagination: {
            total: result.total,
            skip: filters.skip,
            take: filters.take,
          },
        },
      });
    } catch (error: unknown) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid filters',
            details: error.issues,
          },
        });
        return;
      }

      res.status(500).json({
        success: false,
        error: {
          code: 'LIST_RISK_SCORES_FAILED',
          message: getErrorMessage(error) || 'Failed to list risk scores',
        },
      });
    }
  }

  /**
   * EN: Get risk score for user
   * VI: Lấy điểm rủi ro cho user
   */
  async getScore(req: Request, res: Response): Promise<void> {
    try {
      const { userId } = req.params;
      const score = await riskService.getRiskScore(userId);

      res.json({
        success: true,
        data: score,
      });
    } catch (error: unknown) {
      if (error instanceof NotFoundError) {
        res.status(404).json(error.toApiResponse());
        return;
      }

      res.status(500).json({
        success: false,
        error: {
          code: 'GET_RISK_SCORE_FAILED',
          message: getErrorMessage(error) || 'Failed to get risk score',
        },
      });
    }
  }

  /**
   * EN: Calculate risk score
   * VI: Tính điểm rủi ro
   */
  async calculate(req: Request, res: Response): Promise<void> {
    try {
      const data = CalculateRiskScoreDto.parse(req.body);
      const score = await riskService.calculateRiskScore(data.userId, data.factors, req);

      res.json({
        success: true,
        data: score,
        message: 'Risk score calculated successfully / Điểm rủi ro đã được tính thành công',
      });
    } catch (error: unknown) {
      if (error instanceof z.ZodError) {
        res.status(400).json({
          success: false,
          error: {
            code: 'VALIDATION_ERROR',
            message: 'Invalid input',
            details: error.issues,
          },
        });
        return;
      }

      if (error instanceof NotFoundError) {
        res.status(404).json(error.toApiResponse());
        return;
      }

      res.status(500).json({
        success: false,
        error: {
          code: 'CALCULATE_RISK_SCORE_FAILED',
          message: getErrorMessage(error) || 'Failed to calculate risk score',
        },
      });
    }
  }

  /**
   * EN: Get risk dashboard
   * VI: Lấy dashboard rủi ro
   */
  async dashboard(req: Request, res: Response): Promise<void> {
    try {
      const threshold = req.query.threshold ? parseInt(req.query.threshold as string) : 50;
      const highRiskUsers = await riskService.getHighRiskUsers(threshold);

      const allScores = await this.prisma.riskScore.findMany({
        select: { level: true, score: true },
        orderBy: { calculatedAt: 'desc' },
        take: 1000,
      });

      const distribution = {
        LOW: allScores.filter((s) => s.level === 'LOW').length,
        MEDIUM: allScores.filter((s) => s.level === 'MEDIUM').length,
        HIGH: allScores.filter((s) => s.level === 'HIGH').length,
        CRITICAL: allScores.filter((s) => s.level === 'CRITICAL').length,
      };

      const averageScore = allScores.length > 0
        ? allScores.reduce((sum, s) => sum + s.score, 0) / allScores.length
        : 0;

      res.json({
        success: true,
        data: {
          highRiskUsers,
          distribution,
          averageScore: Math.round(averageScore * 100) / 100,
          totalUsers: allScores.length,
        },
      });
    } catch (error: unknown) {
      res.status(500).json({
        success: false,
        error: {
          code: 'GET_DASHBOARD_FAILED',
          message: getErrorMessage(error) || 'Failed to get risk dashboard',
        },
      });
    }
  }
}

export const riskController = new RiskController();
