<?php

namespace App\Models;

use App\Support\PricingModelRegistry;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class PricingTier extends Model
{
    use HasFactory;

    const BILLING_CYCLE_ONE_TIME = 1;
    const BILLING_CYCLE_DAILY = 2;
    const BILLING_CYCLE_WEEKLY = 3;
    const BILLING_CYCLE_MONTHLY = 4;
    const BILLING_CYCLE_QUARTERLY = 5;
    const BILLING_CYCLE_SEMI_ANNUALLY = 6;
    const BILLING_CYCLE_YEARLY = 7;

    const BILLING_CYCLE_UNITS = [
        self::BILLING_CYCLE_ONE_TIME => 'One Time',
        self::BILLING_CYCLE_DAILY => 'Daily',
        self::BILLING_CYCLE_WEEKLY => 'Weekly',
        self::BILLING_CYCLE_MONTHLY => 'Monthly',
        self::BILLING_CYCLE_QUARTERLY => 'Quarterly',
        self::BILLING_CYCLE_SEMI_ANNUALLY => 'Semi-Annually',
        self::BILLING_CYCLE_YEARLY => 'Yearly',
    ];

    const TRIAL_DURATION_UNITS = [
        1 => 'Day(s)',
        2 => 'Week(s)',
        3 => 'Month(s)',
        4 => 'Year(s)',
    ];

    protected $guarded = ['id'];

    protected $casts = [
        'is_default'      => 'boolean',
        'trial_available' => 'boolean',
        'trial_duration'  => 'integer',
        'plan_id'         => 'integer',
        'price'           => 'decimal:2',
        'per_unit_amount' => 'decimal:2',
        'pricing_model'   => 'string',
    ];

    protected $appends = ['trial_duration_unit_label', 'billing_cycle_label'];

    /**
     * Calculate the total price for a given quantity.
     * Delegates to the registered pricing model handler.
     */
    public function calculatePrice(int $quantity = 1): float
    {
        return app(PricingModelRegistry::class)
            ->resolve($this->pricing_model ?? 'fixed')
            ->calculatePrice($this, $quantity);
    }

    public function product()
    {
        return $this->hasOneThrough(Product::class, Plan::class, 'id', 'id', 'plan_id', 'product_id');
    }

    public function plan()
    {
        return $this->belongsTo(Plan::class, 'plan_id');
    }

    public function getFormattedPrice($price)
    {
        $formattedPrice = ch_format_price($price);

        $billingCycleText = getConstantLabel('billing_cycle', $this->billing_cycle);

        if ($this->plan->billing_type == getConstant('BILLING_ONETIME')) {
            return $formattedPrice;
        } else {
            return "{$formattedPrice} / {$billingCycleText}";
        }
    }

    public function orderItems()
    {
        return $this->morphMany(OrderItem::class, 'purchasable');
    }

    public function addons()
    {
        return $this->belongsToMany(
            Addon::class,'addon_pricing_tier',
            'pricing_tier_id',
            'addon_id'
        )->withPivot(['price', 'billing_cycle_override']);
    }

    public function isRecurring()
    {
        return $this->billing_cycle != getConstant('BILLING_CYCLE_ONE_TIME');
    }

    protected function trialDurationUnitLabel(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->trial_duration_unit ? getConstantLabel('trial_duration_unit', $this->trial_duration_unit) : '',
        );
    }

    protected function billingCycleLabel(): Attribute
    {
        return Attribute::make(
            get: fn () => $this->billing_type == getConstant('BILLING_SUBSCRIPTION')
                ? (getConstantLabel('billing_cycle', $this->billing_cycle) ?? 'N/A')
                : getConstantLabel('billing_type', $this->billing_type),
        );
    }

    public function toArray()
    {
        $array = parent::toArray();
        $array['trial_duration_unit_label'] = $this->trial_duration_unit_label;
        $array['billing_cycle_label'] = $this->billing_cycle_label;
        $array['formattedPrice'] = ch_format_price($this->price);
        return $array;
    }
}
