<?php

namespace App\Policy\Entity;

use App\Auth\Entity\User;
use App\Policy\Repository\PolicySimulationRunRepository;
use App\Shared\Tenant\TenantOwnedTrait;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Uid\Uuid;

/**
 * نتیجهٔ یک اجرای آزمایشی — تنها چیزی که شبیه‌سازی می‌نویسد.
 *
 * وجودش دو کار می‌کند: به کاربر نشان می‌دهد قانونش چه می‌کند، و به `activate` اجازهٔ
 * فعال‌سازی می‌دهد. بدون اجرای آزمایشیِ **همین نسخه**، قانون فعال نمی‌شود.
 */
#[ORM\Entity(repositoryClass: PolicySimulationRunRepository::class)]
#[ORM\Table(name: 'policy_simulation_runs')]
#[ORM\Index(columns: ['policy_id', 'policy_version', 'created_at'], name: 'idx_psr_policy')]
#[ORM\Index(columns: ['entity_type', 'entity_id', 'created_at'], name: 'idx_psr_tenant')]
class PolicySimulationRun
{
    use TenantOwnedTrait;

    public const SEVERITY_NONE   = 'none';
    public const SEVERITY_LOW    = 'low';
    public const SEVERITY_MEDIUM = 'medium';
    public const SEVERITY_HIGH   = 'high';

    #[ORM\Id]
    #[ORM\GeneratedValue]
    #[ORM\Column(type: 'integer')]
    private ?int $id = null;

    #[ORM\Column(type: 'string', length: 36, unique: true)]
    private string $uuid;

    #[ORM\ManyToOne(targetEntity: Policy::class)]
    #[ORM\JoinColumn(name: 'policy_id', nullable: false, onDelete: 'CASCADE')]
    private Policy $policy;

    #[ORM\Column(name: 'policy_version', type: 'smallint')]
    private int $policyVersion;

    #[ORM\Column(name: 'sample_size', type: 'smallint')]
    private int $sampleSize;

    #[ORM\Column(name: 'affected_count', type: 'smallint')]
    private int $affectedCount;

    #[ORM\Column(type: 'string', length: 10)]
    private string $severity;

    /** @var array<string, mixed> */
    #[ORM\Column(type: 'json')]
    private array $report;

    #[ORM\ManyToOne(targetEntity: User::class)]
    #[ORM\JoinColumn(name: 'run_by', nullable: true, onDelete: 'SET NULL')]
    private ?User $runBy = null;

    #[ORM\Column(name: 'created_at', type: 'integer')]
    private int $createdAt;

    /** @param array<string, mixed> $report */
    public function __construct(
        Policy $policy,
        int $sampleSize,
        int $affectedCount,
        string $severity,
        array $report,
        ?User $runBy = null,
    ) {
        $this->uuid          = Uuid::v4()->toRfc4122();
        $this->policy        = $policy;
        $this->policyVersion = $policy->getVersion();
        $this->sampleSize    = $sampleSize;
        $this->affectedCount = $affectedCount;
        $this->severity      = $severity;
        $this->report        = $report;
        $this->runBy         = $runBy;
        $this->createdAt     = time();

        $this->entityType = $policy->getEntityType();
        $this->entityId   = $policy->getEntityId();
    }

    /**
     * شدت از **نسبت** می‌آید نه از تعداد: ۷ نوبت از ۱۰ فاجعه است و ۷ از ۵۰۰ عادی.
     *
     * صفر هم هشدار است، نه موفقیت: قانونی که روی هیچ نوبتی اثر ندارد یا شرطش هرگز
     * برقرار نمی‌شود یا نمونه اشتباه انتخاب شده — هر دو باید دیده شوند.
     */
    public static function severityFor(int $sampleSize, int $affected): string
    {
        if ($affected === 0) {
            return self::SEVERITY_NONE;
        }

        $ratio = $sampleSize === 0 ? 0.0 : $affected / $sampleSize;

        return match (true) {
            $ratio > 0.60 => self::SEVERITY_HIGH,
            $ratio > 0.20 => self::SEVERITY_MEDIUM,
            default       => self::SEVERITY_LOW,
        };
    }

    public function getId(): ?int          { return $this->id; }
    public function getUuid(): string      { return $this->uuid; }
    public function getPolicy(): Policy    { return $this->policy; }
    public function getPolicyVersion(): int { return $this->policyVersion; }
    public function getSampleSize(): int   { return $this->sampleSize; }
    public function getAffectedCount(): int { return $this->affectedCount; }
    public function getSeverity(): string  { return $this->severity; }
    public function getCreatedAt(): int    { return $this->createdAt; }

    /** @return array<string, mixed> */
    public function getReport(): array { return $this->report; }

    /** @return array<string, mixed> */
    public function toArray(): array
    {
        return [
            'uuid'           => $this->uuid,
            'policy_uuid'    => $this->policy->getUuid(),
            'policy_version' => $this->policyVersion,
            'sample_size'    => $this->sampleSize,
            'affected_count' => $this->affectedCount,
            'affected_percent' => $this->sampleSize === 0
                ? 0
                : (int) round($this->affectedCount * 100 / $this->sampleSize),
            'severity'       => $this->severity,
            'created_at'     => $this->createdAt,
        ] + $this->report;
    }
}
