<?php

namespace App\Nexus\Engine;

/**
 * NEXUS ENGINE - EvaluationResult
 * 
 * Value object returned by every evaluator in the system.
 * Gives a consistent way to represent the outcome of any
 * bid or sell evaluation across all engine classes.
 *
 * Three possible decisions:
 *   'approved'    - passed evaluation, trade executes normally
 *   'rejected'    - failed evaluation, trade does not execute
 *   'guaranteed'  - bypassed normal evaluation (buyback zone, first-timer)
 *
 * Usage:
 *   $result = EvaluationResult::approved('Passed all criteria', ['score' => 0.87]);
 *   $result = EvaluationResult::rejected('Monthly cap exceeded');
 *   $result = EvaluationResult::guaranteed('First-time seller guarantee');
 *
 *   if ($result->isApproved()) { ... }
 *
 * @package App\Nexus\Engine
 */
class EvaluationResult
{
    /** @var bool Whether the evaluation passed (true for both 'approved' and 'guaranteed') */
    public bool $approved;

    /** @var string One of: 'approved', 'rejected', 'guaranteed' */
    public string $decision;

    /** @var string Human-readable reason for the decision */
    public string $reason;

    /** @var array Full scoring breakdown for audit log */
    public array $scoreData;

    /**
     * Private constructor - use static factory methods.
     */
    private function __construct(bool $approved, string $decision, string $reason, array $scoreData = [])
    {
        $this->approved  = $approved;
        $this->decision  = $decision;
        $this->reason    = $reason;
        $this->scoreData = $scoreData;
    }

    /**
     * Create an approved result.
     * Trade passed normal evaluation and will execute.
     *
     * @param string $reason   Why it was approved
     * @param array  $scoreData Scoring breakdown for audit
     * @return self
     */
    public static function approved(string $reason, array $scoreData = []): self
    {
        return new self(true, 'approved', $reason, $scoreData);
    }

    /**
     * Create a rejected result.
     * Trade failed evaluation and will not execute.
     *
     * @param string $reason   Why it was rejected
     * @param array  $scoreData Scoring breakdown for audit
     * @return self
     */
    public static function rejected(string $reason, array $scoreData = []): self
    {
        return new self(false, 'rejected', $reason, $scoreData);
    }

    /**
     * Create a guaranteed result.
     * Trade bypassed normal evaluation (buyback zone or first-timer).
     * Functionally the same as approved but tracked separately
     * so the audit log and analytics can distinguish organic wins
     * from guaranteed wins.
     *
     * @param string $reason   Why it was guaranteed
     * @param array  $scoreData Scoring breakdown for audit
     * @return self
     */
    public static function guaranteed(string $reason, array $scoreData = []): self
    {
        return new self(true, 'guaranteed', $reason, $scoreData);
    }

    /**
     * Check if the evaluation resulted in a win.
     * Returns true for both 'approved' and 'guaranteed' decisions.
     *
     * @return bool
     */
    public function isApproved(): bool
    {
        return $this->approved;
    }

    /**
     * Check if the evaluation was a guaranteed bypass.
     * Returns true only for 'guaranteed' decisions, not regular approvals.
     *
     * @return bool
     */
    public function isGuaranteed(): bool
    {
        return $this->decision === 'guaranteed';
    }

    /**
     * Check if the evaluation was rejected.
     *
     * @return bool
     */
    public function isRejected(): bool
    {
        return $this->decision === 'rejected';
    }

    /**
     * Convert to array for storage in nexus_audit_log.score_data.
     *
     * @return array
     */
    public function toArray(): array
    {
        return [
            'approved'   => $this->approved,
            'decision'   => $this->decision,
            'reason'     => $this->reason,
            'score_data' => $this->scoreData,
        ];
    }
}
