<?php

namespace Fleetbase\Storefront\Models;

use Fleetbase\Casts\Json;
use Fleetbase\Casts\Money;
use Fleetbase\FleetOps\Models\OrderConfig;
use Fleetbase\FleetOps\Support\Utils;
use Fleetbase\Models\Category;
use Fleetbase\Models\Company;
use Fleetbase\Models\File;
use Fleetbase\Models\Invite;
use Fleetbase\Models\User;
use Fleetbase\Storefront\Support\Storefront;
use Fleetbase\Traits\HasApiModelBehavior;
use Fleetbase\Traits\HasApiModelCache;
use Fleetbase\Traits\HasOptionsAttributes;
use Fleetbase\Traits\HasPublicid;
use Fleetbase\Traits\HasUuid;
use Fleetbase\Traits\Searchable;
use Illuminate\Support\Str;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;

class Network extends StorefrontModel
{
    use HasUuid;
    use HasPublicid;
    use HasApiModelBehavior;
    use HasApiModelCache;
    use HasOptionsAttributes;
    use HasSlug;
    use Searchable;

    /**
     * The type of public Id to generate.
     *
     * @var string
     */
    protected $publicIdType = 'network';

    /**
     * The database table used by the model.
     *
     * @var string
     */
    protected $table = 'networks';

    /**
     * These attributes that can be queried.
     *
     * @var array
     */
    protected $searchableColumns = ['name', 'description'];

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = ['created_by_uuid', 'company_uuid', 'logo_uuid', 'backdrop_uuid', 'order_config_uuid', 'key', 'online', 'name', 'description', 'website', 'facebook', 'instagram', 'twitter', 'email', 'phone', 'translations', 'tags', 'currency', 'timezone', 'pod_method', 'options', 'alertable', 'slug'];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'options'      => Json::class,
        'translations' => Json::class,
        'alertable'    => Json::class,
        'tags'         => 'array',
        'online'       => 'boolean',
    ];

    /**
     * Dynamic attributes that are appended to object.
     *
     * @var array
     */
    protected $appends = ['logo_url', 'backdrop_url', 'stores_count'];

    /**
     * The attributes excluded from the model's JSON form.
     *
     * @var array
     */
    protected $hidden = ['logo', 'backdrop', 'files', 'media'];

    /**
     * @var SlugOptions
     */
    public function getSlugOptions(): SlugOptions
    {
        return SlugOptions::create()
            ->generateSlugsFrom('name')
            ->saveSlugsTo('slug');
    }

    /** on boot generate key */
    public static function boot()
    {
        parent::boot();
        static::creating(function ($model) {
            $model->key = 'network_' . md5(Str::random(14) . time());
        });
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function createdBy()
    {
        return $this->setConnection(config('fleetbase.connection.db'))->belongsTo(User::class);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function company()
    {
        return $this->setConnection(config('fleetbase.connection.db'))->belongsTo(Company::class);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function logo()
    {
        return $this->setConnection(config('fleetbase.connection.db'))->belongsTo(File::class);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function backdrop()
    {
        return $this->setConnection(config('fleetbase.connection.db'))->belongsTo(File::class);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function orderConfig()
    {
        return $this->setConnection(config('fleetbase.connection.db'))->belongsTo(OrderConfig::class);
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function files()
    {
        return $this->setConnection(config('fleetbase.connection.db'))->hasMany(File::class, 'subject_uuid');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function media()
    {
        return $this->files()->where('type', 'storefront_network_media');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasManyThrough
     */
    public function stores()
    {
        return $this->belongsToMany(Store::class, 'network_stores', 'network_uuid', 'store_uuid')
            ->using(NetworkStore::class)
            ->withPivot(['category_uuid', 'deleted_at'])
            ->wherePivotNull('deleted_at');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function notificationChannels()
    {
        return $this->hasMany(NotificationChannel::class, 'owner_uuid');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function gateways()
    {
        return $this->hasMany(Gateway::class, 'owner_uuid');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\HasMany
     */
    public function invitations()
    {
        return $this->setConnection(config('fleetbase.connection.db'))->hasMany(Invite::class, 'subject_uuid');
    }

    /**
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
     */
    public function categories()
    {
        return $this->setConnection(config('fleetbase.connection.db'))->hasMany(Category::class, 'owner_uuid')->where(['for' => 'network_category']);
    }

    /**
     * @var string
     */
    public function getLogoUrlAttribute()
    {
        // return static::attributeFromCache($this, 'logo.url', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/image-file-icon.png');
        return $this->logo->url ?? 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/image-file-icon.png';
    }

    /**
     * @var string
     */
    public function getBackdropUrlAttribute()
    {
        // return static::attributeFromCache($this, 'backdrop.url', 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/default-storefront-backdrop.png');
        return $this->backdrop->url ?? 'https://flb-assets.s3.ap-southeast-1.amazonaws.com/static/default-storefront-backdrop.png';
    }

    /**
     * @var int
     */
    public function getStoresCountAttribute()
    {
        return $this->stores()->count();
    }

    /**
     * Mutator for the `options` attribute.
     * Allows special handling for nested keys while keeping JSON casting intact.
     */
    public function setOptionsAttribute($value)
    {
        // Ensure we operate on a PHP array
        if (is_string($value)) {
            $value = json_decode($value, true) ?? [];
        }

        if (!is_array($value)) {
            $value = [];
        }

        // Special handling for `required_checkout_min_amount`
        if (array_key_exists('required_checkout_min_amount', $value)) {
            $value['required_checkout_min_amount'] = Money::apply($value['required_checkout_min_amount']);
        }

        // Assign the array back — JSON cast handles encoding
        $this->attributes['options'] = $value;
    }

    /**
     * Adds a new store to the network.
     */
    public function addStore(Store $store, ?Category $category = null): NetworkStore
    {
        return NetworkStore::updateOrCreate(
            [
                'network_uuid' => $this->uuid,
                'store_uuid'   => $store->uuid,
            ],
            [
                'network_uuid'  => $this->uuid,
                'store_uuid'    => $store->uuid,
                'category_uuid' => $category instanceof Category ? $category->uuid : null,
            ]
        );
    }

    /**
     *'Create a new network store category for this store record.
     *
     * @param File|string|null $icon
     * @param string           $iconColor
     */
    public function createCategory(string $name, string $description = '', ?array $meta = [], ?array $translations = [], ?Category $parent = null, $icon = null, $iconColor = '#000000'): Category
    {
        $iconFile = null;
        $iconName = null;

        if ($icon instanceof File) {
            $iconFile = $icon;
        }

        if (is_string($icon)) {
            $iconName = $icon;
        }

        return Category::create([
            'company_uuid'   => $this->company_uuid,
            'owner_uuid'     => $this->uuid,
            'owner_type'     => Utils::getMutationType('network:storefront'),
            'parent_uuid'    => $parent instanceof Category ? $parent->uuid : null,
            'icon_file_uuid' => $iconFile->uuid,
            'for'            => 'storefront_network',
            'name'           => $name,
            'description'    => $description,
            'translations'   => $translations,
            'meta'           => $meta,
            'icon'           => $iconName,
            'icon_color'     => $iconColor,
        ]);
    }

    /**
     * Create a new network store category if it doesn't already exists for this store record.
     *
     * @param File|string|null $icon
     * @param string           $iconColor
     */
    public function createCategoryStrict(string $name, string $description = '', ?array $meta = [], ?array $translations = [], ?Category $parent = null, $icon = null, $iconColor = '#000000'): Category
    {
        $existingCategory = Category::where(['company_uuid' => $this->company_uuid, 'owner_uuid' => $this->uuid, 'name' => $name])->first();

        if ($existingCategory) {
            return $existingCategory;
        }

        return $this->createCategory($name, $description, $meta, $translations, $parent, $icon, $iconColor);
    }

    /**
     * Get the effective OrderConfig for this model.
     *
     * Loads the related `orderConfig` if missing and returns it.
     * If no specific config is set, it falls back to the global default
     * and memoizes that default into the relation (no DB write; just the relation cache)
     * to avoid repeat lookups in the same request lifecycle.
     *
     * @throws \RuntimeException if no default OrderConfig is available (should not happen in a healthy install)
     */
    public function getOrderConfig(): OrderConfig
    {
        // Ensure relation is loaded once
        $this->loadMissing('orderConfig');

        if ($this->orderConfig instanceof OrderConfig) {
            return $this->orderConfig;
        }

        // Fallback to default (must exist in your environment)
        $default = Storefront::getDefaultOrderConfig();

        if (!$default instanceof OrderConfig) {
            // Keep your hard return type contract honest
            throw new \RuntimeException('No default OrderConfig is configured.');
        }

        // Memoize the fallback in the in-memory relation to avoid repeated lookups
        $this->setRelation('orderConfig', $default);

        return $default;
    }

    /**
     * Get the UUID of the effective OrderConfig for this model.
     *
     * Tries to use the local FK if present to avoid loading the relation;
     * otherwise, resolves via getOrderConfig() (which memoizes).
     *
     * @return string non-empty UUID of the effective order config
     */
    public function getOrderConfigId(): string
    {
        // Fast path: if the FK column is set, use it directly
        if (!empty($this->order_config_uuid)) {
            return (string) $this->order_config_uuid;
        }

        // Otherwise rely on the resolved config (relation or default)
        return (string) $this->getOrderConfig()->uuid;
    }
}
