<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;

class Plan extends Model
{
    use HasFactory;

    protected $fillable = [
        'name',
        'description',
        'product_id',
        'pricing_id',
        'shoppy_product_id',
        'accept_stripe',
        'accept_shoppy',
        'oxapay_link',
        'accept_oxapay',
        'price',
        'mailbox_limit',
        'monthly_billing',
        'details',
        // New fields for enhanced plan system
        'plan_tier_id',
        'billing_cycle_days',
        'is_active',
        'sort_order',
        'metadata',
    ];

    protected $casts = [
        'details' => 'json',
        'monthly_billing' => 'boolean',
        'accept_stripe' => 'boolean',
        'accept_shoppy' => 'boolean',
        'accept_oxapay' => 'boolean',
        'is_active' => 'boolean',
        'metadata' => 'array',
    ];

    /**
     * Get the plan tier that this plan belongs to
     */
    public function planTier(): BelongsTo
    {
        return $this->belongsTo(PlanTier::class);
    }

    /**
     * Get feature limits for this plan
     */
    public function planFeatureLimits(): HasMany
    {
        return $this->hasMany(PlanFeatureLimit::class);
    }

    /**
     * Get permissions for this plan
     */
    public function planPermissions(): HasMany
    {
        return $this->hasMany(PlanPermission::class);
    }

    /**
     * Get payment providers for this plan
     */
    public function planProviders(): HasMany
    {
        return $this->hasMany(PlanProvider::class);
    }

    /**
     * Get trial configuration for this plan
     */
    public function trialConfiguration(): HasOne
    {
        return $this->hasOne(TrialConfiguration::class);
    }

    /**
     * Get subscriptions for this plan
     */
    public function subscriptions(): HasMany
    {
        return $this->hasMany(Subscription::class);
    }

    /**
     * Get usage tracking for this plan
     */
    public function planUsages(): HasMany
    {
        return $this->hasMany(PlanUsage::class);
    }

    /**
     * Get features associated with this plan (through limits)
     */
    public function features(): BelongsToMany
    {
        return $this->belongsToMany(PlanFeature::class, 'plan_feature_limits')
            ->withPivot(['limit_value', 'is_enabled', 'limit_type', 'applies_during_trial', 'trial_limit_value'])
            ->withTimestamps();
    }

    /**
     * Scope: Active plans
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope: Ordered by sort order
     */
    public function scopeOrdered($query)
    {
        return $query->orderBy('sort_order')->orderBy('name');
    }

    /**
     * Scope: By tier
     */
    public function scopeByTier($query, $tierId)
    {
        return $query->where('plan_tier_id', $tierId);
    }

    /**
     * Check if plan has a specific feature enabled
     */
    public function hasFeature(string $featureName): bool
    {
        $featureLimit = $this->planFeatureLimits()
            ->whereHas('planFeature', function ($query) use ($featureName) {
                $query->where('name', $featureName);
            })
            ->first();

        return $featureLimit && $featureLimit->isEnabled();
    }

    /**
     * Check if user can use a feature within limits
     */
    public function canUseFeature(string $featureName, float $currentUsage = 0, bool $isOnTrial = false): bool
    {
        $featureLimit = $this->planFeatureLimits()
            ->whereHas('planFeature', function ($query) use ($featureName) {
                $query->where('name', $featureName);
            })
            ->first();

        return $featureLimit ? $featureLimit->canUseFeature($currentUsage, $isOnTrial) : false;
    }

    /**
     * Get remaining usage for a feature
     */
    public function getRemainingUsage(string $featureName, float $currentUsage = 0, bool $isOnTrial = false): float
    {
        $featureLimit = $this->planFeatureLimits()
            ->whereHas('planFeature', function ($query) use ($featureName) {
                $query->where('name', $featureName);
            })
            ->first();

        return $featureLimit ? $featureLimit->getRemainingUsage($currentUsage, $isOnTrial) : 0;
    }

    /**
     * Check if plan has a specific permission
     */
    public function hasPermission(string $featureName, string $permission, bool $isOnTrial = false): bool
    {
        $planPermission = $this->planPermissions()
            ->whereHas('planFeature', function ($query) use ($featureName) {
                $query->where('name', $featureName);
            })
            ->where('permission', $permission)
            ->first();

        return $planPermission ? $planPermission->isEffectivePermission($isOnTrial) : false;
    }

    /**
     * Get allowed payment providers for this plan
     */
    public function getAllowedProviders(): array
    {
        return $this->planProviders()
            ->enabled()
            ->orderBy('sort_order')
            ->pluck('provider')
            ->toArray();
    }

    /**
     * Check if plan supports a specific payment provider
     */
    public function supportsProvider(string $provider): bool
    {
        return $this->planProviders()
            ->where('provider', $provider)
            ->where('is_enabled', true)
            ->exists();
    }

    /**
     * Get provider configuration for a specific provider
     */
    public function getProviderConfig(string $provider): ?PlanProvider
    {
        return $this->planProviders()
            ->where('provider', $provider)
            ->where('is_enabled', true)
            ->first();
    }

    /**
     * Check if plan has trial enabled
     */
    public function hasTrial(): bool
    {
        return $this->trialConfiguration && $this->trialConfiguration->trial_enabled;
    }

    /**
     * Get trial configuration
     */
    public function getTrialConfig(): ?TrialConfiguration
    {
        return $this->trialConfiguration?->trial_enabled ? $this->trialConfiguration : null;
    }

    /**
     * Get billing cycle in human readable format
     */
    public function getBillingCycleDisplay(): string
    {
        if ($this->billing_cycle_days) {
            if ($this->billing_cycle_days == 30) {
                return 'Monthly';
            }
            if ($this->billing_cycle_days == 90) {
                return 'Quarterly';
            }
            if ($this->billing_cycle_days == 365) {
                return 'Yearly';
            }

            return "{$this->billing_cycle_days} days";
        }

        return $this->monthly_billing ? 'Monthly' : 'Yearly';
    }

    /**
     * Calculate Monthly Recurring Revenue (MRR) for this plan
     */
    public function calculateMRR(): float
    {
        if (! $this->price) {
            return 0;
        }

        // Use the new billing cycle system if available
        if ($this->billing_cycle_days) {
            return ($this->price / $this->billing_cycle_days) * 30;
        }

        // Fallback to legacy system
        $cycleDays = $this->monthly_billing ? 30 : 365;

        return ($this->price / $cycleDays) * 30;
    }

    /**
     * Get monthly price attribute for compatibility
     */
    public function getMonthlyPriceAttribute(): float
    {
        return $this->calculateMRR();
    }

    /**
     * Get plan metadata value
     */
    public function getMetadata(?string $key = null, $default = null)
    {
        if ($key) {
            return data_get($this->metadata, $key, $default);
        }

        return $this->metadata;
    }

    /**
     * Set plan metadata value
     */
    public function setMetadata(string $key, $value): void
    {
        $data = $this->metadata ?? [];
        data_set($data, $key, $value);
        $this->metadata = $data;
    }

    /**
     * Get all features with their limits and permissions
     */
    public function getFeaturesWithLimits(): array
    {
        return $this->planFeatureLimits()
            ->with('planFeature')
            ->get()
            ->map(function ($limit) {
                return [
                    'feature' => $limit->planFeature,
                    'limit' => $limit,
                    'permissions' => $this->planPermissions()
                        ->where('plan_feature_id', $limit->plan_feature_id)
                        ->get(),
                ];
            })
            ->toArray();
    }

    /**
     * Check if this plan is an upgrade from another plan
     */
    public function isUpgradeFrom(Plan $otherPlan): bool
    {
        // Simple logic: check if this plan has higher tier or price
        if ($this->planTier_id && $otherPlan->planTier_id) {
            return $this->planTier->sort_order > $otherPlan->planTier->sort_order;
        }

        return $this->price > $otherPlan->price;
    }

    /**
     * Get upgrade path to this plan
     */
    public function getUpgradePath(): array
    {
        // Return plans that can be upgraded to this plan
        return Plan::where('id', '!=', $this->id)
            ->where(function ($query) {
                $query->where('price', '<', $this->price)
                    ->orWhereHas('planTier', function ($q) {
                        $q->where('sort_order', '<', $this->planTier?->sort_order ?? 0);
                    });
            })
            ->active()
            ->ordered()
            ->get()
            ->toArray();
    }
}
