<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Location extends Model
{
    public const TYPE_WAREHOUSE = 'warehouse';
    public const TYPE_STORE = 'store';

    protected $fillable = [
        'company_id',
        'code',
        'name',
        'type',
        'phone',
        'email',
        'address_line1',
        'address_line2',
        'city',
        'state',
        'pincode',
        'country',
        'latitude',
        'longitude',
        'timezone',
        'is_active',
        'fulfills_online',
        'allows_pickup',
        'priority',
        'is_default',
    ];

    protected function casts(): array
    {
        return [
            'latitude' => 'float',
            'longitude' => 'float',
            'is_active' => 'boolean',
            'fulfills_online' => 'boolean',
            'allows_pickup' => 'boolean',
            'is_default' => 'boolean',
            'priority' => 'integer',
        ];
    }

    public function company(): BelongsTo
    {
        return $this->belongsTo(Company::class);
    }

    public function settings(): HasMany
    {
        return $this->hasMany(LocationSetting::class);
    }

    public function inventoryBalances(): HasMany
    {
        return $this->hasMany(InventoryBalance::class);
    }

    public function users(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'store_user')
            ->withPivot('is_default')
            ->withTimestamps();
    }

    public function cashRegisters(): HasMany
    {
        return $this->hasMany(CashRegister::class);
    }

    public function isWarehouse(): bool
    {
        return $this->type === self::TYPE_WAREHOUSE;
    }

    public function isStore(): bool
    {
        return $this->type === self::TYPE_STORE;
    }

    public function scopeActive(Builder $query): Builder
    {
        return $query->where('is_active', true);
    }

    public function scopeStores(Builder $query): Builder
    {
        return $query->where('type', self::TYPE_STORE);
    }

    public function scopeWarehouses(Builder $query): Builder
    {
        return $query->where('type', self::TYPE_WAREHOUSE);
    }

    /**
     * Locations that may sell online: active stores with fulfills_online.
     * Warehouses are supply points only — never counted in online stock.
     */
    public function scopeFulfillsOnline(Builder $query): Builder
    {
        return $query->where('type', self::TYPE_STORE)
            ->where('fulfills_online', true)
            ->where('is_active', true);
    }

    public function scopeAllowsPickup(Builder $query): Builder
    {
        return $query->where('allows_pickup', true)->where('is_active', true);
    }

    public function getSetting(string $key, mixed $default = null): mixed
    {
        $setting = $this->settings()->where('key', $key)->first();

        return $setting?->value ?? $default;
    }

    public function setSetting(string $key, mixed $value): LocationSetting
    {
        return $this->settings()->updateOrCreate(
            ['key' => $key],
            ['value' => is_array($value) || is_object($value) ? json_encode($value) : (string) $value]
        );
    }

    public static function defaultStore(): ?self
    {
        return static::query()
            ->stores()
            ->where('is_default', true)
            ->active()
            ->first()
            ?? static::query()->stores()->active()->orderBy('priority')->first();
    }

    public static function centralWarehouse(): ?self
    {
        return static::query()
            ->warehouses()
            ->where('is_default', true)
            ->active()
            ->first()
            ?? static::query()->warehouses()->active()->orderBy('id')->first();
    }

    public function fullAddress(): string
    {
        return collect([
            $this->address_line1,
            $this->address_line2,
            $this->city,
            $this->state,
            $this->pincode,
        ])->filter()->implode(', ');
    }
}
