<?php

namespace App\Models\Catalog;

use App\Models\Concerns\Auditable;
use App\Models\Concerns\BelongsToTenant;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\SoftDeletes;
use RuntimeException;

class MainCategory extends Model
{
    use Auditable, BelongsToTenant, SoftDeletes;

    /**
     * The one system category the application itself depends on: products
     * filed under it are ordinary products in every respect (pricing, stock,
     * tax, SKU, cart, invoicing) — the POS simply presents them in their own
     * fixed strip instead of the scrolling product grid.
     *
     * Rows are tenant-scoped, so ids differ per tenant and are useless as a
     * shared reference. `sort_code` is the stable per-tenant key, and this is
     * the single place it is spelled out.
     */
    public const SYSTEM_PACKAGING = 'PKG';

    public const SYSTEM_PACKAGING_NAME = 'Packaging & Add-ons';

    protected $fillable = ['name', 'sort_code', 'description', 'is_active', 'is_system'];

    protected function casts(): array
    {
        return ['is_active' => 'boolean', 'is_system' => 'boolean'];
    }

    /**
     * Renaming is blocked because the name is what operators recognise the
     * category by, and `sort_code` because {@see self::packaging()} resolves
     * on it. Everything else (description, is_active) stays tenant-editable.
     */
    protected static function booted(): void
    {
        static::updating(function (self $category): void {
            if (! $category->getOriginal('is_system')) {
                return;
            }

            if ($category->isDirty(['name', 'sort_code', 'is_system'])) {
                throw new RuntimeException("The \"{$category->getOriginal('name')}\" category is a system category and cannot be renamed.");
            }
        });
    }

    /**
     * Model-level, not just UI-level: a system category must survive a delete
     * attempted from anywhere — a Filament action, tinker, or a screen nobody
     * has written yet. Guarded here rather than on the `deleting` event so it
     * fires before Auditable's listener stamps `deleted_by` on the way out.
     */
    public function delete(): ?bool
    {
        if ($this->is_system) {
            throw new RuntimeException("The \"{$this->name}\" category is a system category and cannot be deleted.");
        }

        return parent::delete();
    }

    /** The tenant's "Packaging & Add-ons" category, or null before it is seeded. */
    public static function packaging(): ?self
    {
        return static::query()->where('sort_code', self::SYSTEM_PACKAGING)->first();
    }

    public function subCategories(): HasMany
    {
        return $this->hasMany(SubCategory::class);
    }

    public function products(): HasMany
    {
        return $this->hasMany(Product::class);
    }
}
