<?php

declare(strict_types=1);

namespace App\Models;

use App\Notifications\SubscriptionRequestNotification;
use App\Traits\MultiTenantScope;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\SoftDeletes;

/**
 * Subscription Request Model.
 *
 * Tracks requests from Company Admins for subscription changes.
 * Super Admin reviews and approves/rejects these requests.
 *
 * WORKFLOW:
 * 1. Company Admin creates request (status: pending)
 * 2. Super Admin reviews (status: approved/rejected)
 * 3. If approved, Super Admin implements change (status: implemented)
 *
 * @property int $id
 * @property int $company_id
 * @property int|null $subscription_id
 * @property int $requested_by_user_id
 * @property string $request_type
 * @property int|null $requested_plan_id
 * @property string|null $current_value
 * @property string|null $requested_value
 * @property string $comments
 * @property string $status
 * @property int|null $reviewed_by_user_id
 * @property Carbon|null $reviewed_at
 * @property string|null $admin_notes
 * @property Carbon|null $implemented_at
 * @property int|null $implemented_by_user_id
 * @property array|null $implementation_details
 * @property int $priority
 * @property Carbon|null $expires_at
 * @property Carbon $created_at
 * @property Carbon $updated_at
 * @property Carbon|null $deleted_at
 * @property-read Company $company
 * @property-read Subscription|null $subscription
 * @property-read User $requestedBy
 * @property-read Plan|null $requestedPlan
 * @property-read User|null $reviewedBy
 * @property-read User|null $implementedBy
 */
class SubscriptionRequest extends Model
{
    use HasFactory, MultiTenantScope, SoftDeletes;

    // ═══════════════════════════════════════════════════════════════════════════
    // CONSTANTS
    // ═══════════════════════════════════════════════════════════════════════════

    // Request Types
    public const TYPE_UPGRADE_PLAN = 'upgrade_plan';

    public const TYPE_DOWNGRADE_PLAN = 'downgrade_plan';

    public const TYPE_INCREASE_USERS = 'increase_users';

    public const TYPE_INCREASE_COLLECTORS = 'increase_collectors';

    public const TYPE_INCREASE_CREDITS = 'increase_credits';

    public const TYPE_INCREASE_VOLUME = 'increase_volume';

    public const TYPE_INCREASE_CLIENTS = 'increase_clients';

    public const TYPE_CUSTOM_FEATURE = 'custom_feature';

    public const TYPE_BILLING_CHANGE = 'billing_change';

    public const TYPE_OTHER = 'other';

    // Statuses
    public const STATUS_PENDING = 'pending';

    public const STATUS_APPROVED = 'approved';

    public const STATUS_REJECTED = 'rejected';

    public const STATUS_CANCELED = 'canceled';

    public const STATUS_IMPLEMENTED = 'implemented';

    // Priorities
    public const PRIORITY_URGENT = 1;

    public const PRIORITY_HIGH = 3;

    public const PRIORITY_NORMAL = 5;

    public const PRIORITY_LOW = 7;

    protected $fillable = [
        'company_id',
        'subscription_id',
        'requested_by_user_id',
        'request_type',
        'requested_plan_id',
        'current_value',
        'requested_value',
        'comments',
        'status',
        'reviewed_by_user_id',
        'reviewed_at',
        'admin_notes',
        'implemented_at',
        'implemented_by_user_id',
        'implementation_details',
        'priority',
        'expires_at',
    ];

    protected $casts = [
        'reviewed_at' => 'datetime',
        'implemented_at' => 'datetime',
        'expires_at' => 'datetime',
        'implementation_details' => 'array',
        'priority' => 'integer',
    ];

    protected $attributes = [
        'status' => self::STATUS_PENDING,
        'priority' => self::PRIORITY_NORMAL,
    ];

    // ═══════════════════════════════════════════════════════════════════════════
    // BOOT
    // ═══════════════════════════════════════════════════════════════════════════

    protected static function boot(): void
    {
        parent::boot();

        // Notify Super Admins when a new request is created
        static::created(function (SubscriptionRequest $request) {
            $request->notifySuperAdmins('created');
        });
    }

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

    /**
     * The company making the request.
     */
    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    /**
     * The subscription at the time of request.
     */
    public function subscription(): BelongsTo
    {
        return $this->belongsTo(Subscription::class);
    }

    /**
     * User who created the request (Company Admin).
     */
    public function requestedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'requested_by_user_id');
    }

    /**
     * The plan being requested (for upgrades/downgrades).
     */
    public function requestedPlan(): BelongsTo
    {
        return $this->belongsTo(Plan::class, 'requested_plan_id');
    }

    /**
     * Super Admin who reviewed the request.
     */
    public function reviewedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'reviewed_by_user_id');
    }

    /**
     * User who implemented the change.
     */
    public function implementedBy(): BelongsTo
    {
        return $this->belongsTo(User::class, 'implemented_by_user_id');
    }

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

    /**
     * Pending requests awaiting review.
     */
    public function scopePending($query)
    {
        return $query->where('status', self::STATUS_PENDING);
    }

    /**
     * Approved but not yet implemented.
     */
    public function scopeApproved($query)
    {
        return $query->where('status', self::STATUS_APPROVED);
    }

    /**
     * Order by priority (urgent first).
     */
    public function scopeByPriority($query)
    {
        return $query->orderBy('priority')->orderBy('created_at');
    }

    /**
     * Requests for Super Admin dashboard.
     */
    public function scopeForReview($query)
    {
        return $query->pending()
            ->byPriority()
            ->with(['company', 'requestedBy', 'requestedPlan']);
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // STATUS CHECKS
    // ═══════════════════════════════════════════════════════════════════════════

    public function isPending(): bool
    {
        return $this->status === self::STATUS_PENDING;
    }

    public function isApproved(): bool
    {
        return $this->status === self::STATUS_APPROVED;
    }

    public function isRejected(): bool
    {
        return $this->status === self::STATUS_REJECTED;
    }

    public function isCanceled(): bool
    {
        return $this->status === self::STATUS_CANCELED;
    }

    public function isImplemented(): bool
    {
        return $this->status === self::STATUS_IMPLEMENTED;
    }

    public function canBeReviewed(): bool
    {
        return $this->isPending();
    }

    public function canBeCanceled(): bool
    {
        return $this->isPending();
    }

    public function canBeImplemented(): bool
    {
        return $this->isApproved();
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // STATUS TRANSITIONS
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * Approve the request.
     */
    public function approve(int $userId, ?string $notes = null): bool
    {
        if (! $this->canBeReviewed()) {
            return false;
        }

        $this->status = self::STATUS_APPROVED;
        $this->reviewed_by_user_id = $userId;
        $this->reviewed_at = now();
        $this->admin_notes = $notes;

        $saved = $this->save();

        if ($saved) {
            $this->notifyRequestedBy('approved');
        }

        return $saved;
    }

    /**
     * Reject the request.
     */
    public function reject(int $userId, ?string $reason = null): bool
    {
        if (! $this->canBeReviewed()) {
            return false;
        }

        $this->status = self::STATUS_REJECTED;
        $this->reviewed_by_user_id = $userId;
        $this->reviewed_at = now();
        $this->admin_notes = $reason;

        $saved = $this->save();

        if ($saved) {
            $this->notifyRequestedBy('rejected');
        }

        return $saved;
    }

    /**
     * Cancel the request (by Company Admin).
     */
    public function cancel(): bool
    {
        if (! $this->canBeCanceled()) {
            return false;
        }

        $this->status = self::STATUS_CANCELED;

        return $this->save();
    }

    /**
     * Mark as implemented.
     */
    public function markImplemented(int $userId, ?array $details = null): bool
    {
        if (! $this->canBeImplemented()) {
            return false;
        }

        $this->status = self::STATUS_IMPLEMENTED;
        $this->implemented_at = now();
        $this->implemented_by_user_id = $userId;
        $this->implementation_details = $details;

        $saved = $this->save();

        if ($saved) {
            $this->notifyRequestedBy('implemented');
        }

        return $saved;
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // ACCESSORS
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * Get request type label.
     */
    public function getRequestTypeLabelAttribute(): string
    {
        return match ($this->request_type) {
            self::TYPE_UPGRADE_PLAN => 'Upgrade de Plan',
            self::TYPE_DOWNGRADE_PLAN => 'Downgrade de Plan',
            self::TYPE_INCREASE_USERS => 'Más Usuarios',
            self::TYPE_INCREASE_COLLECTORS => 'Más Cobradores',
            self::TYPE_INCREASE_CREDITS => 'Más Créditos Activos',
            self::TYPE_INCREASE_VOLUME => 'Mayor Volumen Mensual',
            self::TYPE_INCREASE_CLIENTS => 'Más Clientes',
            self::TYPE_CUSTOM_FEATURE => 'Funcionalidad Personalizada',
            self::TYPE_BILLING_CHANGE => 'Cambio de Facturación',
            self::TYPE_OTHER => 'Otro',
            default => ucfirst(str_replace('_', ' ', $this->request_type)),
        };
    }

    /**
     * Get status label.
     */
    public function getStatusLabelAttribute(): string
    {
        return match ($this->status) {
            self::STATUS_PENDING => 'Pendiente',
            self::STATUS_APPROVED => 'Aprobado',
            self::STATUS_REJECTED => 'Rechazado',
            self::STATUS_CANCELED => 'Cancelado',
            self::STATUS_IMPLEMENTED => 'Implementado',
            default => ucfirst($this->status),
        };
    }

    /**
     * Get status badge color.
     */
    public function getStatusColorAttribute(): string
    {
        return match ($this->status) {
            self::STATUS_PENDING => 'warning',
            self::STATUS_APPROVED => 'info',
            self::STATUS_REJECTED => 'danger',
            self::STATUS_CANCELED => 'gray',
            self::STATUS_IMPLEMENTED => 'success',
            default => 'gray',
        };
    }

    /**
     * Get priority label.
     */
    public function getPriorityLabelAttribute(): string
    {
        return match (true) {
            $this->priority <= 2 => 'Urgente',
            $this->priority <= 4 => 'Alta',
            $this->priority <= 6 => 'Normal',
            default => 'Baja',
        };
    }

    /**
     * Get priority color.
     */
    public function getPriorityColorAttribute(): string
    {
        return match (true) {
            $this->priority <= 2 => 'danger',
            $this->priority <= 4 => 'warning',
            $this->priority <= 6 => 'info',
            default => 'gray',
        };
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // NOTIFICATIONS
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * Notify the user who created the request.
     */
    public function notifyRequestedBy(string $event): void
    {
        $user = $this->requestedBy;
        if ($user) {
            $user->notify(new SubscriptionRequestNotification($this, $event));
        }
    }

    /**
     * Notify all Super Admins about new request.
     */
    public function notifySuperAdmins(string $event = 'created'): void
    {
        $superAdmins = User::role('super_admin')->get();

        foreach ($superAdmins as $admin) {
            $admin->notify(new SubscriptionRequestNotification($this, $event));
        }
    }

    // ═══════════════════════════════════════════════════════════════════════════
    // STATIC HELPERS
    // ═══════════════════════════════════════════════════════════════════════════

    /**
     * Get pending requests count for Super Admin badge.
     */
    public static function pendingCount(): int
    {
        return static::pending()->count();
    }

    /**
     * Get pending requests for a company.
     */
    public static function pendingForCompany(int $companyId): int
    {
        return static::where('company_id', $companyId)
            ->pending()
            ->count();
    }

    /**
     * Check if company has reached max pending requests.
     */
    public static function canCreateRequest(int $companyId, int $maxPending = 3): bool
    {
        return static::pendingForCompany($companyId) < $maxPending;
    }

    /**
     * Get available request types.
     */
    public static function getRequestTypes(): array
    {
        return [
            self::TYPE_UPGRADE_PLAN => 'Upgrade de Plan',
            self::TYPE_DOWNGRADE_PLAN => 'Downgrade de Plan',
            self::TYPE_INCREASE_USERS => 'Más Usuarios',
            self::TYPE_INCREASE_COLLECTORS => 'Más Cobradores',
            self::TYPE_INCREASE_CREDITS => 'Más Créditos Activos',
            self::TYPE_INCREASE_VOLUME => 'Mayor Volumen Mensual',
            self::TYPE_INCREASE_CLIENTS => 'Más Clientes',
            self::TYPE_CUSTOM_FEATURE => 'Funcionalidad Personalizada',
            self::TYPE_BILLING_CHANGE => 'Cambio de Facturación',
            self::TYPE_OTHER => 'Otro',
        ];
    }
}
