<?php

declare(strict_types=1);

namespace PpPhp\Core\Diagnostics\Results;

use PpPhp\Core\Diagnostics\Severity;

final class DiagnosticResult
{
    /** @var DiagnosticIssue[] */
    private array $issues = [];

    public function __construct(
        private readonly string $providerId,
        private readonly string $providerLabel,
        private readonly string $category = 'platform'
    ) {
    }

    public function providerId(): string
    {
        return $this->providerId;
    }

    public function providerLabel(): string
    {
        return $this->providerLabel;
    }

    public function category(): string
    {
        return $this->category;
    }

    public function add(DiagnosticIssue $issue): void
    {
        $this->issues[] = $issue;
    }

    public function info(string $message, string $source = '', string $suggestion = '', array $metadata = []): void
    {
        $this->add(DiagnosticIssue::info($message, $source, $suggestion, $metadata));
    }

    public function warning(string $message, string $source = '', string $suggestion = '', bool $repairable = false, array $metadata = []): void
    {
        $this->add(DiagnosticIssue::warning($message, $source, $suggestion, $repairable, $metadata));
    }

    public function error(string $message, string $source = '', string $suggestion = '', bool $repairable = false, array $metadata = []): void
    {
        $this->add(DiagnosticIssue::error($message, $source, $suggestion, $repairable, $metadata));
    }

    public function critical(string $message, string $source = '', string $suggestion = '', bool $repairable = false, array $metadata = []): void
    {
        $this->add(DiagnosticIssue::critical($message, $source, $suggestion, $repairable, $metadata));
    }

    /** @return DiagnosticIssue[] */
    public function issues(): array
    {
        return $this->issues;
    }

    public function countBySeverity(string $severity): int
    {
        return count(array_filter(
            $this->issues,
            static fn (DiagnosticIssue $issue): bool => $issue->severity === $severity
        ));
    }

    public function problemCount(): int
    {
        return count(array_filter(
            $this->issues,
            static fn (DiagnosticIssue $issue): bool => $issue->isProblem()
        ));
    }

    public function penalty(): int
    {
        return array_sum(array_map(
            static fn (DiagnosticIssue $issue): int => Severity::weight($issue->severity),
            $this->issues
        ));
    }

    public function toArray(): array
    {
        return [
            'providerId' => $this->providerId,
            'providerLabel' => $this->providerLabel,
            'category' => $this->category,
            'issues' => array_map(
                static fn (DiagnosticIssue $issue): array => $issue->toArray(),
                $this->issues
            ),
        ];
    }
}
