<?php

namespace App\Nexus\Models;

use App\Models\Ownership;
use App\Models\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\DB;

/**
 * NEXUS User Metrics - per-user tracking for the engine.
 *
 * One row per user (user_id is UNIQUE). Monthly profit resets via lazy reset
 * in SellEvaluator Step 4 when the 30-day cycle expires.
 *
 * Columns used by engine classes:
 *   consecutive_losses     - Step 3 (Loss Requirement)
 *   monthly_profit         - Step 4 (current profit tracking)
 *   daily_profit           - Step 4 (daily budget pacing)
 *   weekly_profit          - Step 4 (weekly budget pacing)
 *   daily_budget           - Step 4 (randomized daily allowance)
 *   weekly_budget          - Step 4 (randomized weekly allowance)
 *   effective_cap_percent  - Step 4 (capital-weighted cap, for dashboard visibility)
 *   day_date               - Step 4 (which date daily_profit belongs to)
 *   week_started_at        - Step 4 (when current week started)
 *   metrics_reset_at       - Step 4 (lazy 30-day cycle start)
 *   first_sell_granted     - first-time seller guarantee (Step 2)
 *   first_bid_win_used     - first-time bidder guarantee (BidEvaluator Step 5)
 *   total_bids/wins/losses - metrics
 *   total_sells_approved/rejected - sell metrics
 *   total_earned           - lifetime earnings
 *
 * DEPRECATED (left on table, no code reads them):
 *   monthly_capital        - replaced by live calculateActiveCapital()
 *   monthly_profit_cap     - replaced by effective_cap_percent (capital-weighted)
 */
class NexusUserMetric extends Model
{
    protected $table = 'nexus_user_metrics';

    protected $fillable = [
        'user_id',
        'monthly_profit',
        'monthly_profit_cap',
        'monthly_capital',
        'effective_cap_percent',
        'weekly_profit',
        'weekly_budget',
        'week_started_at',
        'daily_profit',
        'daily_budget',
        'day_date',
        'total_sells_approved',
        'total_sells_rejected',
        'consecutive_losses',
        'total_bids',
        'total_wins',
        'total_losses',
        'first_sell_granted',
        'first_bid_win_used',
        'total_earned',
        'ictp_base',
        'metrics_reset_at',
    ];

    protected $casts = [
        'monthly_profit'        => 'decimal:2',
        'monthly_profit_cap'    => 'decimal:2',
        'monthly_capital'       => 'decimal:2',
        'effective_cap_percent' => 'decimal:2',
        'weekly_profit'         => 'decimal:2',
        'weekly_budget'         => 'decimal:2',
        'daily_profit'          => 'decimal:2',
        'total_earned'          => 'decimal:2',
        'ictp_base'             => 'decimal:2',
        'first_sell_granted'    => 'integer',
        'first_bid_win_used'    => 'integer',
        'consecutive_losses'    => 'integer',
        'total_bids'            => 'integer',
        'total_wins'            => 'integer',
        'total_losses'          => 'integer',
        'metrics_reset_at'      => 'datetime',
        'week_started_at'       => 'datetime',
        'day_date'              => 'date',
    ];

    // ── RELATIONSHIPS ──

    public function user()
    {
        return $this->belongsTo(User::class, 'user_id');
    }

    // ── STATIC HELPERS ──

    /**
     * Get or create metrics row for a user.
     * One row per user (user_id is UNIQUE).
     */
    public static function forUser(int $userId): static
    {
        return static::firstOrCreate(
            ['user_id' => $userId],
            [
                'monthly_profit'       => 0,
                'monthly_capital'      => 0,
                'total_sells_approved' => 0,
                'total_sells_rejected' => 0,
                'consecutive_losses'   => 0,
                'total_bids'           => 0,
                'total_wins'           => 0,
                'total_losses'         => 0,
                'first_sell_granted'   => 0,
                'first_bid_win_used'   => 0,
                'total_earned'         => 0,
            ]
        );
    }

    /**
     * Alias for forUser() -- used by engine classes.
     * The $monthYear parameter is accepted but ignored.
     * This table uses one row per user with monthly reset,
     * not one row per user per month.
     *
     * @param int    $userId
     * @param string $monthYear Ignored (kept for engine compatibility)
     * @return static
     */
    public static function getOrCreate(int $userId, string $monthYear = ''): static
    {
        return static::forUser($userId);
    }

    /**
     * Calculate live active capital for a user.
     *
     * active_capital = user.balance + user.ictp_balance + SUM(ownerships value)
     *
     * This replaces the dead monthly_capital column. Calculated live on every
     * evaluation so it always reflects the user's current state (deposits,
     * withdrawals, recycled capital all handled automatically).
     *
     * @param User $user The user (must be a loaded model instance)
     * @return float
     */
    public static function calculateActiveCapital(User $user): float
    {
        $balance = (float) $user->balance;
        $ictpBalance = (float) ($user->ictp_balance ?? 0);
        $ownershipValue = (float) Ownership::where('user_id', $user->id)
            ->sum(DB::raw('`value` * `quantity`'));

        return $balance + $ictpBalance + $ownershipValue;
    }

    // ── ACCESSORS FOR ENGINE COMPATIBILITY ──

    /**
     * Engine references first_sell_win_used.
     * Maps to first_sell_granted on this table.
     */
    public function getFirstSellWinUsedAttribute(): int
    {
        return (int) $this->first_sell_granted;
    }

    /**
     * Allow engine to set first_sell_win_used.
     * Maps to first_sell_granted.
     */
    public function setFirstSellWinUsedAttribute($value): void
    {
        $this->attributes['first_sell_granted'] = $value;
    }

    // ── INSTANCE HELPERS ──

    /**
     * Has this user used their first-timer sell guarantee?
     */
    public function hasUsedFirstTimerGuarantee(): bool
    {
        return $this->first_sell_granted >= 1;
    }

    /**
     * Has this user hit their monthly profit cap?
     * DEPRECATED: Use SellEvaluator step4_ProfitCapCheck() instead.
     * Kept for backward compatibility with any dashboard queries.
     */
    public function isAtMonthlyCapFor(float $sellAmount): bool
    {
        if (is_null($this->monthly_profit_cap)) return false;
        return ($this->monthly_profit + $sellAmount) > $this->monthly_profit_cap;
    }

    /**
     * Remaining profit allowed this month.
     * DEPRECATED: Use SellEvaluator step4_ProfitCapCheck() instead.
     */
    public function remainingMonthlyAllowance(): float
    {
        if (is_null($this->monthly_profit_cap)) return PHP_FLOAT_MAX;
        return max(0, (float) $this->monthly_profit_cap - (float) $this->monthly_profit);
    }

    /**
     * Record an approved sell.
     * Called inside the engine's atomic execution block.
     */
    public function recordApprovedSell(float $amount): void
    {
        $this->increment('total_sells_approved');
        $this->increment('total_wins');
        $this->increment('monthly_profit', $amount);
        $this->increment('total_earned', $amount);
        $this->update(['consecutive_losses' => 0]); // Reset on win
    }

    /**
     * Record a rejected sell.
     */
    public function recordRejectedSell(): void
    {
        $this->increment('total_sells_rejected');
        $this->increment('total_losses');
        $this->increment('consecutive_losses');
    }

    /**
     * Reset all profit tracking for a new 30-day cycle.
     * Called by SellEvaluator lazy reset (inline in Step 4).
     */
    public function resetMonthlyProfit(): void
    {
        $this->update([
            'monthly_profit'    => 0,
            'monthly_capital'   => 0,
            'weekly_profit'     => 0,
            'weekly_budget'     => null,
            'week_started_at'   => null,
            'daily_profit'      => 0,
            'daily_budget'      => null,
            'day_date'          => null,
            'metrics_reset_at'  => now(),
        ]);
    }
}
