<?php

namespace Modules\Inventory\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\SoftDeletes;
use Modules\Accounts\Models\Traits\HasVatTransactions;
use Modules\Billing\Models\Traits\HasBillingItems;
use Modules\Core\Enums\AmountTypeEnum;
use Modules\Core\Enums\PriceTypeEnum;
use Modules\Core\Enums\VatTypeEnum;
use Modules\Core\Traits\AuditableTrait;
use Modules\Core\Traits\HasStatus;
use Modules\Inventory\Enums\CategoryTypeEnum;
use Modules\Inventory\Models\Traits\HasCategory;
use Modules\Inventory\Models\Traits\HasInventoryDepartment;
use Modules\Inventory\Models\Traits\HasBaseUnit;
use Modules\Inventory\Models\Traits\HasStockBatches;
use Modules\Inventory\Models\Traits\ProductRelationshipTrait;
use Modules\Inventory\Models\Traits\HasStockMovements;

class Product extends Model
{
    use HasInventoryDepartment,
        HasCategory,
        HasBaseUnit,
        ProductRelationshipTrait,
        HasStockBatches,
        HasStockMovements,
        HasBillingItems,
        HasStatus,
        AuditableTrait,
        HasVatTransactions,
        SoftDeletes;

    /**
     * The attributes that are mass assignable.
     */
    protected $fillable = [
        'name',
        'sku',
        'barcode',
        'image',
        'inventory_department_id',
        'category_id',
        'inventory_account_id',
        'cogs_account_id',
        'sales_account_id',
        'expense_account_id',
        'asset_account_id',
        'accum_dep_account_id',
        'dep_expense_account_id',
        'base_unit_id',
        'product_type',
        'mrp',
        'default_selling_price',
        'vat_price_type',
        'vat_type',
        'vat_rate',
        'subsidy_type',
        'subsidy_value',
        'has_stock',
        'has_batch',
        'has_expiry',
        'has_unit_conversion',
        'alert_qty',
        'shelf_no',
        'status',
        'created_by',
    ];

    protected function casts(): array
    {
        return [
            'has_stock' => 'boolean',
            'has_batch' => 'boolean',
            'has_expiry' => 'boolean',
            'has_unit_conversion' => 'boolean',
        ];
    }

    public function getSellingPriceAttribute(): float
    {
        $price = (float) $this->default_selling_price;

        if ($this->subsidy_value <= 0) {
            return $price;
        }

        return match ($this->subsidy_type) {
            AmountTypeEnum::FIXED->value => max(0,
                $price - $this->subsidy_value
            ),
            AmountTypeEnum::PERCENTAGE->value => max(0,
                $price - (($price * $this->subsidy_value) / 100)
            ),

            default => $price,
        };
    }

    public function getAvailableStockAttribute(): float
    {
        if (!$this->stock) {
            return 0;
        }

        return ((float) $this->stock->current_qty - (float) $this->stock->reserved_qty);
    }

    public function scopeSearch(Builder $query, ?string $search): Builder
    {
        if (blank($search)) {
            return $query;
        }

        return $query->where(function ($q) use ($search) {
            $like = "%{$search}%";

            $q->where('name', 'LIKE', $like)
                ->orWhere('sku', 'LIKE', $like)
                ->orWhereHas('category', function ($q) use ($like) {
                    $q->where('name', 'LIKE', $like);
                });;
        });
    }

    public function scopeByType(Builder $query, ?string $type): Builder
    {
        return $type ? $query->where('product_type', $type) : $query;
    }

    public function scopePurchaseProducts(Builder $query): Builder
    {
        return $query
            ->active()
            ->whereHas('category', function ($q) {
                $q->whereIn('category_type', [
                    CategoryTypeEnum::INVENTORY->value,
                    CategoryTypeEnum::EXPENSE->value,
                ]);
            });
    }

    public function scopeAssetProducts(Builder $query): Builder
    {
        return $query
            ->active()
            ->whereHas('category', function ($q) {
                $q->where('category_type', CategoryTypeEnum::ASSET->value);
            });
    }

    public function scopeSaleProducts(Builder $query): Builder
    {
        return $query
            ->active()
            ->where('has_stock', true)
            ->whereHas('category', function ($q) {
                $q->where('category_type', CategoryTypeEnum::INVENTORY->value);
            });
    }

    public function scopeWithPurchaseRelations(Builder $query): Builder
    {
        return $query->with([
            'baseUnit:id,name',
            'category:id,name,category_type',
            'purchaseUnitConversions:id,product_id,from_unit_id,from_qty,to_qty,is_default_purchase',
            'purchaseUnitConversions.fromUnit:id,name',
        ]);
    }

    public function scopeWithSaleRelations(Builder $query): Builder
    {
        return $query->with([
            'baseUnit:id,name',
            'category:id,name,category_type',
            'stock:id,product_id,current_qty,reserved_qty',
            'saleUnitConversions:id,product_id,from_unit_id,from_qty,to_qty,is_default_sale',
            'saleUnitConversions.fromUnit:id,name',
        ]);
    }

    protected function netPrice(): Attribute
    {
        return Attribute::get(function () {
            $price = (float) $this->default_selling_price;
            $rate = (float) $this->vat_rate;

            if ($this->vat_type !== VatTypeEnum::STANDARD->value || $rate <= 0) {
                return round($price, 2);
            }

            if ($this->price_type === PriceTypeEnum::INCLUSIVE->value) {
                return round($price / (1 + ($rate / 100)), 2);
            }

            return round($price, 2);
        });
    }

    protected function grossPrice(): Attribute
    {
        return Attribute::get(function () {
            $price = (float) $this->default_selling_price;
            $rate = (float) $this->vat_rate;

            if ($this->vat_type !== VatTypeEnum::STANDARD->value || $rate <= 0) {
                return round($price, 2);
            }

            if ($this->price_type === PriceTypeEnum::EXCLUSIVE->value) {
                return round($price * (1 + ($rate / 100)), 2);
            }

            return round($price, 2);
        });
    }
}
