<?php

declare(strict_types=1);

namespace App\Application\Security;

use App\Framework\Attributes\Route;
use App\Framework\Core\ValueObjects\Timestamp;
use App\Framework\Http\HttpRequest;
use App\Framework\Http\Method;
use App\Framework\Router\Result\ViewResult;
use App\Framework\Waf\DetectionCategory;
use App\Framework\Waf\Feedback\FeedbackRepositoryInterface;
use App\Framework\Waf\Feedback\FeedbackService;
use App\Framework\Waf\Feedback\FeedbackType;

/**
 * Controller for the WAF feedback dashboard
 */
final readonly class WafFeedbackDashboardController
{
    /**
     * @param FeedbackRepositoryInterface $repository Repository for accessing feedback data
     * @param FeedbackService $feedbackService Service for handling WAF feedback
     */
    public function __construct(
        private FeedbackRepositoryInterface $repository,
        private FeedbackService $feedbackService
    ) {
    }

    /**
     * Show the WAF feedback dashboard
     */
    #[Route(path: '/admin/security/waf/feedback', method: Method::GET)]
    public function showDashboard(HttpRequest $request): ViewResult
    {
        // Get feedback statistics
        $stats = $this->repository->getFeedbackStats();

        // Get recent feedback
        $recentFeedback = $this->repository->getRecentFeedback(10);

        // Get time period from query parameters (default to last 30 days)
        $period = $request->queryParams['period'] ?? '30d';
        $since = $this->getPeriodTimestamp($period);

        // Get feedback by type for the selected period
        $falsePositives = $this->repository->getFeedbackByFeedbackType(
            FeedbackType::FALSE_POSITIVE,
            $since
        );

        $falseNegatives = $this->repository->getFeedbackByFeedbackType(
            FeedbackType::FALSE_NEGATIVE,
            $since
        );

        $correctDetections = $this->repository->getFeedbackByFeedbackType(
            FeedbackType::CORRECT_DETECTION,
            $since
        );

        $severityAdjustments = $this->repository->getFeedbackByFeedbackType(
            FeedbackType::SEVERITY_ADJUSTMENT,
            $since
        );

        // Calculate accuracy metrics
        $totalFeedback = count($falsePositives) + count($falseNegatives) + count($correctDetections);
        $accuracy = $totalFeedback > 0
            ? (count($correctDetections) / $totalFeedback) * 100
            : 0;

        $falsePositiveRate = $totalFeedback > 0
            ? (count($falsePositives) / $totalFeedback) * 100
            : 0;

        $falseNegativeRate = $totalFeedback > 0
            ? (count($falseNegatives) / $totalFeedback) * 100
            : 0;

        // Get feedback by category
        $feedbackByCategory = $this->getFeedbackByCategory($since);

        // Get trend data
        $trendData = $stats['trend_data'] ?? [];

        return new ViewResult('admin/security/waf-feedback-dashboard', [
            'stats' => $stats,
            'recent_feedback' => $recentFeedback,
            'period' => $period,
            'accuracy' => round($accuracy, 1),
            'false_positive_rate' => round($falsePositiveRate, 1),
            'false_negative_rate' => round($falseNegativeRate, 1),
            'feedback_by_category' => $feedbackByCategory,
            'trend_data' => $trendData,
            'false_positives_count' => count($falsePositives),
            'false_negatives_count' => count($falseNegatives),
            'correct_detections_count' => count($correctDetections),
            'severity_adjustments_count' => count($severityAdjustments),
        ]);
    }

    /**
     * Show detailed feedback for a specific category
     */
    #[Route(path: '/admin/security/waf/feedback/category/{category}', method: Method::GET)]
    public function showCategoryFeedback(HttpRequest $request, string $category): ViewResult
    {
        try {
            $detectionCategory = DetectionCategory::from($category);
        } catch (\ValueError $e) {
            // If category is invalid, redirect to dashboard
            return new ViewResult('admin/security/waf-feedback-dashboard', [
                'error' => 'Invalid category: ' . $category,
            ]);
        }

        // Get time period from query parameters (default to last 30 days)
        $period = $request->queryParams['period'] ?? '30d';
        $since = $this->getPeriodTimestamp($period);

        // Get feedback for this category
        $feedback = $this->repository->getFeedbackByCategory($detectionCategory, $since);

        // Group feedback by type
        $feedbackByType = [];
        foreach ($feedback as $item) {
            $type = $item->feedbackType->value;
            if (! isset($feedbackByType[$type])) {
                $feedbackByType[$type] = [];
            }
            $feedbackByType[$type][] = $item;
        }

        // Calculate accuracy metrics for this category
        $falsePositives = $feedbackByType[FeedbackType::FALSE_POSITIVE->value] ?? [];
        $falseNegatives = $feedbackByType[FeedbackType::FALSE_NEGATIVE->value] ?? [];
        $correctDetections = $feedbackByType[FeedbackType::CORRECT_DETECTION->value] ?? [];

        $totalFeedback = count($falsePositives) + count($falseNegatives) + count($correctDetections);
        $accuracy = $totalFeedback > 0
            ? (count($correctDetections) / $totalFeedback) * 100
            : 0;

        $falsePositiveRate = $totalFeedback > 0
            ? (count($falsePositives) / $totalFeedback) * 100
            : 0;

        $falseNegativeRate = $totalFeedback > 0
            ? (count($falseNegatives) / $totalFeedback) * 100
            : 0;

        return new ViewResult('admin/security/waf-feedback-category', [
            'category' => $detectionCategory,
            'feedback' => $feedback,
            'feedback_by_type' => $feedbackByType,
            'period' => $period,
            'accuracy' => round($accuracy, 1),
            'false_positive_rate' => round($falsePositiveRate, 1),
            'false_negative_rate' => round($falseNegativeRate, 1),
            'total_feedback' => $totalFeedback,
        ]);
    }

    /**
     * Show feedback learning history
     */
    #[Route(path: '/admin/security/waf/feedback/learning', method: Method::GET)]
    public function showLearningHistory(HttpRequest $request): ViewResult
    {
        // In a real implementation, this would retrieve learning history from a database
        // For now, we'll return a placeholder view

        return new ViewResult('admin/security/waf-feedback-learning', [
            'learning_history' => [],
            'message' => 'Learning history not yet implemented',
        ]);
    }

    /**
     * Get a timestamp for the specified period
     *
     * @param string $period Period string (e.g., '7d', '30d', '90d', 'all')
     * @return Timestamp|null Timestamp for the start of the period, or null for 'all'
     */
    private function getPeriodTimestamp(string $period): ?Timestamp
    {
        return match($period) {
            '7d' => Timestamp::fromString('-7 days'),
            '30d' => Timestamp::fromString('-30 days'),
            '90d' => Timestamp::fromString('-90 days'),
            'all' => null,
            default => Timestamp::fromString('-30 days')
        };
    }

    /**
     * Get feedback grouped by category
     *
     * @param Timestamp|null $since Optional timestamp to filter feedback after a certain date
     * @return array<string, array<string, mixed>> Feedback data grouped by category
     */
    private function getFeedbackByCategory(?Timestamp $since): array
    {
        $result = [];

        // Get all categories
        $categories = DetectionCategory::cases();

        foreach ($categories as $category) {
            // Get feedback for this category
            $feedback = $this->repository->getFeedbackByCategory($category, $since);

            if (empty($feedback)) {
                continue;
            }

            // Group feedback by type
            $feedbackByType = [];
            foreach ($feedback as $item) {
                $type = $item->feedbackType->value;
                if (! isset($feedbackByType[$type])) {
                    $feedbackByType[$type] = [];
                }
                $feedbackByType[$type][] = $item;
            }

            // Calculate metrics
            $falsePositives = $feedbackByType[FeedbackType::FALSE_POSITIVE->value] ?? [];
            $falseNegatives = $feedbackByType[FeedbackType::FALSE_NEGATIVE->value] ?? [];
            $correctDetections = $feedbackByType[FeedbackType::CORRECT_DETECTION->value] ?? [];

            $totalFeedback = count($falsePositives) + count($falseNegatives) + count($correctDetections);

            if ($totalFeedback === 0) {
                continue;
            }

            $accuracy = (count($correctDetections) / $totalFeedback) * 100;

            $result[$category->value] = [
                'category' => $category,
                'total_feedback' => $totalFeedback,
                'false_positives' => count($falsePositives),
                'false_negatives' => count($falseNegatives),
                'correct_detections' => count($correctDetections),
                'accuracy' => round($accuracy, 1),
            ];
        }

        // Sort by total feedback count (descending)
        uasort($result, fn ($a, $b) => $b['total_feedback'] <=> $a['total_feedback']);

        return $result;
    }
}
