<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Carbon\Carbon;

class Subscription extends Model
{
    protected $fillable = [
        'user_id',
        'tenant_id',
        'plan_id',
        'plan',
        'status',
        'razorpay_subscription_id',
        'razorpay_customer_id',
        'trial_ends_at',
        'current_period_start',
        'current_period_end',
        'cancelled_at',
        'ends_at',
        'metadata',
    ];

    protected $casts = [
        'trial_ends_at' => 'datetime',
        'current_period_start' => 'datetime',
        'current_period_end' => 'datetime',
        'cancelled_at' => 'datetime',
        'ends_at' => 'datetime',
        'metadata' => 'array',
    ];

    // Status constants
    const STATUS_ACTIVE = 'active';
    const STATUS_TRIALING = 'trialing';
    const STATUS_PAST_DUE = 'past_due';
    const STATUS_CANCELLED = 'cancelled';
    const STATUS_EXPIRED = 'expired';
    const STATUS_INCOMPLETE = 'incomplete';

    /**
     * Get the user that owns the subscription.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Get the tenant that owns the subscription.
     */
    public function tenant(): BelongsTo
    {
        return $this->belongsTo(Tenant::class);
    }

    /**
     * Get the plan for this subscription.
     */
    public function planModel(): BelongsTo
    {
        return $this->belongsTo(Plan::class, 'plan_id');
    }

    /**
     * Get the transactions for this subscription.
     */
    public function transactions(): HasMany
    {
        return $this->hasMany(SubscriptionTransaction::class);
    }

    /**
     * Get the invoices for this subscription.
     */
    public function invoices(): HasMany
    {
        return $this->hasMany(SubscriptionInvoice::class);
    }

    /**
     * Get the feature usage for this subscription.
     */
    public function featureUsage(): HasMany
    {
        return $this->hasMany(SubscriptionFeatureUsage::class);
    }

    /**
     * Check if the subscription is active.
     */
    public function isActive(): bool
    {
        return $this->status === self::STATUS_ACTIVE && !$this->isExpired();
    }

    /**
     * Check if the subscription is on trial.
     */
    public function onTrial(): bool
    {
        return $this->status === self::STATUS_TRIALING && 
               $this->trial_ends_at && 
               $this->trial_ends_at->isFuture();
    }

    /**
     * Check if the subscription is cancelled.
     */
    public function isCancelled(): bool
    {
        return $this->status === self::STATUS_CANCELLED || $this->cancelled_at !== null;
    }

    /**
     * Check if the subscription is expired.
     */
    public function isExpired(): bool
    {
        if ($this->ends_at && $this->ends_at->isPast()) {
            return true;
        }

        if ($this->current_period_end && $this->current_period_end->isPast() && 
            $this->status !== self::STATUS_ACTIVE) {
            return true;
        }

        return false;
    }

    /**
     * Check if the subscription is past due.
     */
    public function isPastDue(): bool
    {
        return $this->status === self::STATUS_PAST_DUE;
    }

    /**
     * Check if the subscription is valid (active or on trial).
     */
    public function isValid(): bool
    {
        return $this->isActive() || $this->onTrial();
    }

    /**
     * Get days remaining in current period.
     */
    public function daysRemaining(): int
    {
        if (!$this->current_period_end) {
            return 0;
        }

        return max(0, now()->diffInDays($this->current_period_end, false));
    }

    /**
     * Get days remaining in trial.
     */
    public function trialDaysRemaining(): int
    {
        if (!$this->onTrial() || !$this->trial_ends_at) {
            return 0;
        }

        return max(0, now()->diffInDays($this->trial_ends_at, false));
    }

    /**
     * Cancel the subscription.
     */
    public function cancel(bool $immediately = false): bool
    {
        $this->cancelled_at = now();
        
        if ($immediately) {
            $this->status = self::STATUS_CANCELLED;
            $this->ends_at = now();
        } else {
            // Cancel at period end
            $this->ends_at = $this->current_period_end ?? now();
        }

        return $this->save();
    }

    /**
     * Resume a cancelled subscription.
     */
    public function resume(): bool
    {
        if (!$this->isCancelled()) {
            return false;
        }

        $this->cancelled_at = null;
        $this->ends_at = null;
        $this->status = self::STATUS_ACTIVE;

        return $this->save();
    }

    /**
     * Mark subscription as expired.
     */
    public function markAsExpired(): bool
    {
        $this->status = self::STATUS_EXPIRED;
        $this->ends_at = now();

        return $this->save();
    }

    /**
     * Renew the subscription for the next period.
     */
    public function renew(): bool
    {
        $plan = $this->planModel;
        
        if (!$plan) {
            return false;
        }

        $this->current_period_start = now();
        $this->current_period_end = now()->addMonth();
        $this->status = self::STATUS_ACTIVE;

        return $this->save();
    }

    /**
     * Check if user can use a specific feature.
     */
    public function canUseFeature(string $feature): bool
    {
        if (!$this->isValid()) {
            return false;
        }

        $plan = $this->planModel;
        
        if (!$plan) {
            return false;
        }

        // Check if feature has a limit
        $limit = $plan->getAttribute($feature);
        
        // -1 means unlimited
        if ($limit === -1) {
            return true;
        }

        // Get current usage for this period
        $usage = $this->getCurrentUsage($feature);

        return $usage < $limit;
    }

    /**
     * Get current usage for a feature.
     */
    public function getCurrentUsage(string $feature): int
    {
        $periodStart = $this->current_period_start ?? now()->startOfMonth();
        $periodEnd = $this->current_period_end ?? now()->endOfMonth();

        $usage = $this->featureUsage()
            ->where('feature', $feature)
            ->where('period_start', '<=', $periodEnd)
            ->where('period_end', '>=', $periodStart)
            ->first();

        return $usage ? $usage->used : 0;
    }

    /**
     * Increment feature usage.
     */
    public function incrementUsage(string $feature, int $amount = 1): bool
    {
        $periodStart = $this->current_period_start ?? now()->startOfMonth();
        $periodEnd = $this->current_period_end ?? now()->endOfMonth();

        $plan = $this->planModel;
        $limit = $plan ? $plan->getAttribute($feature) : 0;

        $usage = $this->featureUsage()->updateOrCreate(
            [
                'feature' => $feature,
                'period_start' => $periodStart->toDateString(),
                'period_end' => $periodEnd->toDateString(),
            ],
            [
                'user_id' => $this->user_id,
                'used' => \DB::raw("used + {$amount}"),
                'limit' => $limit,
            ]
        );

        return true;
    }

    /**
     * Get the plan limits.
     */
    public function getPlanLimits(): array
    {
        $plan = $this->planModel;
        
        if (!$plan) {
            return [];
        }

        return [
            'social_accounts' => [
                'limit' => $plan->max_social_accounts,
                'used' => $this->user->socialAccounts()->count(),
                'unlimited' => $plan->max_social_accounts === -1,
            ],
            'campaigns' => [
                'limit' => $plan->max_campaigns,
                'used' => $this->getCurrentUsage('max_campaigns'),
                'unlimited' => $plan->max_campaigns === -1,
            ],
            'proposals' => [
                'limit' => $plan->max_proposals,
                'used' => $this->getCurrentUsage('max_proposals'),
                'unlimited' => $plan->max_proposals === -1,
            ],
            'content_ideas' => [
                'limit' => $plan->max_content_ideas_per_month,
                'used' => $this->getCurrentUsage('max_content_ideas_per_month'),
                'unlimited' => $plan->max_content_ideas_per_month === -1,
            ],
            'reels' => [
                'limit' => $plan->max_reels_per_month,
                'used' => $this->getCurrentUsage('max_reels_per_month'),
                'unlimited' => $plan->max_reels_per_month === -1,
            ],
        ];
    }

    /**
     * Scope to get only active subscriptions.
     */
    public function scopeActive($query)
    {
        return $query->where('status', self::STATUS_ACTIVE)
                     ->where(function ($q) {
                         $q->whereNull('ends_at')
                           ->orWhere('ends_at', '>', now());
                     });
    }

    /**
     * Scope to get only valid subscriptions (active or trialing).
     */
    public function scopeValid($query)
    {
        return $query->whereIn('status', [self::STATUS_ACTIVE, self::STATUS_TRIALING])
                     ->where(function ($q) {
                         $q->whereNull('ends_at')
                           ->orWhere('ends_at', '>', now());
                     });
    }
}
