<?php

declare(strict_types=1);

namespace App\Models;

use App\Enums\OwnershipModel;
use App\Enums\PartnerStatus;
use App\Traits\MultiTenantScope;
use App\ValueObjects\Money;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

/**
 * Socio / Inversionista.
 *
 * Cada socio pertenece a una compania (multi-tenant) y puede tener:
 * - Aportes de capital (capital_contributions)
 * - Retiros (partner_withdrawals)
 * - Lineas de distribucion de utilidades (profitDistributionLines)
 *
 * El modelo de propiedad puede ser:
 * - FIXED: Porcentaje asignado manualmente, no cambia con aportes.
 * - DYNAMIC: Se calcula como (capital_neto_socio / capital_neto_total) * 100
 *
 * @property int $id
 * @property int $company_id
 * @property string $name
 * @property string|null $document_type
 * @property string|null $document_number
 * @property string|null $email
 * @property string|null $phone
 * @property OwnershipModel $ownership_model
 * @property string|null $fixed_ownership_percentage
 * @property PartnerStatus $status
 * @property Carbon $joined_at
 * @property Carbon|null $exited_at
 * @property string|null $notes
 * @property array|null $metadata
 */
class Partner extends Model
{
    use MultiTenantScope;

    protected $fillable = [
        'company_id',
        'name',
        'document_type',
        'document_number',
        'email',
        'phone',
        'ownership_model',
        'fixed_ownership_percentage',
        'status',
        'joined_at',
        'exited_at',
        'notes',
        'metadata',
    ];

    protected $casts = [
        'ownership_model' => OwnershipModel::class,
        'fixed_ownership_percentage' => 'decimal:4',
        'status' => PartnerStatus::class,
        'joined_at' => 'date',
        'exited_at' => 'date',
        'metadata' => 'array',
    ];

    protected $attributes = [
        'ownership_model' => 'dynamic',
        'status' => 'active',
    ];

    // ═══════════════════════════════════════════════════════════════════════
    // RELATIONSHIPS
    // ═══════════════════════════════════════════════════════════════════════

    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    public function contributions(): HasMany
    {
        return $this->hasMany(CapitalContribution::class);
    }

    public function withdrawals(): HasMany
    {
        return $this->hasMany(PartnerWithdrawal::class);
    }

    public function profitDistributionLines(): HasMany
    {
        return $this->hasMany(ProfitDistributionLine::class);
    }

    // ═══════════════════════════════════════════════════════════════════════
    // FINANCIAL CALCULATIONS (using BC Math via Money VO)
    // ═══════════════════════════════════════════════════════════════════════

    /**
     * Total capital contributed by this partner.
     */
    public function getTotalContributed(): Money
    {
        $sum = $this->contributions()->sum('amount');

        return Money::of($sum);
    }

    /**
     * Total withdrawn by this partner (approved only).
     */
    public function getTotalWithdrawn(): Money
    {
        $sum = $this->withdrawals()
            ->where('approval_status', 'approved')
            ->sum('amount');

        return Money::of($sum);
    }

    /**
     * Total capital returned (withdrawals that reduce capital, not profit withdrawals).
     */
    public function getTotalCapitalReturned(): Money
    {
        $sum = $this->withdrawals()
            ->where('approval_status', 'approved')
            ->where('type', 'capital_return')
            ->sum('amount');

        return Money::of($sum);
    }

    /**
     * Net capital balance = contributions - capital_returns.
     * Profit withdrawals do NOT reduce capital balance.
     */
    public function getNetCapital(): Money
    {
        return $this->getTotalContributed()->subtract($this->getTotalCapitalReturned());
    }

    /**
     * Total profits received by this partner.
     */
    public function getTotalProfitsReceived(): Money
    {
        $sum = $this->withdrawals()
            ->where('approval_status', 'approved')
            ->whereIn('type', ['profit_withdrawal', 'dividend_payment'])
            ->sum('amount');

        return Money::of($sum);
    }

    /**
     * Current balance = contributions - all approved withdrawals.
     * This is the partner's total "account" (capital + undistributed profits).
     */
    public function getCurrentBalance(): Money
    {
        return $this->getTotalContributed()->subtract($this->getTotalWithdrawn());
    }

    /**
     * Return on Investment as a percentage.
     * ROI = (total_profits_received / total_contributed) * 100
     */
    public function getReturnOnInvestment(): string
    {
        $contributed = $this->getTotalContributed();

        if ($contributed->isZero()) {
            return '0.00';
        }

        $profits = $this->getTotalProfitsReceived();

        return bcmul(
            bcdiv($profits->toString(), $contributed->toString(), 8),
            '100',
            2
        );
    }

    // ═══════════════════════════════════════════════════════════════════════
    // STATUS HELPERS
    // ═══════════════════════════════════════════════════════════════════════

    public function isActive(): bool
    {
        return $this->status === PartnerStatus::ACTIVE;
    }

    // ═══════════════════════════════════════════════════════════════════════
    // SCOPES
    // ═══════════════════════════════════════════════════════════════════════

    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }
}
