<?php

namespace App\Models\Machine;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

use App\Traits\TenantScoped;

class Machine extends Model
{
    use HasFactory, TenantScoped;
    use \Illuminate\Database\Eloquent\SoftDeletes;

    protected static function booted()
    {
        // 權限隔離：一般帳號登入時只能看到自己被分配的機台
        static::addGlobalScope('machine_access', function (\Illuminate\Database\Eloquent\Builder $builder) {
            $user = auth()->user();
            // 如果是在 Console、或是系統管理員，則不限制 (可看所有機台)
            if (app()->runningInConsole() || !$user || $user->isSystemAdmin()) {
                return;
            }

            // 一般租戶帳號：限制只能看自己擁有的機台
            $builder->whereExists(function ($query) use ($user) {
                $query->select(\Illuminate\Support\Facades\DB::raw(1))
                    ->from('machine_user')
                    ->whereColumn('machine_user.machine_id', 'machines.id')
                    ->where('machine_user.user_id', $user->id);
            });
        });
    }

    protected $fillable = [
        'company_id',
        'name',
        'serial_no',
        'model',
        'location',
        'current_page',
        'door_status',
        'temperature',
        'firmware_version',
        'api_token',
        'last_heartbeat_at',
        'card_reader_seconds',
        'card_reader_checkout_time_1',
        'card_reader_checkout_time_2',
        'heating_start_time',
        'heating_end_time',
        'payment_buffer_seconds',
        'card_reader_no',
        'key_no',
        'invoice_status',
        'welcome_gift_enabled',
        'is_spring_slot_1_10',
        'is_spring_slot_11_20',
        'is_spring_slot_21_30',
        'is_spring_slot_31_40',
        'is_spring_slot_41_50',
        'is_spring_slot_51_60',
        'member_system_enabled',
        'payment_config_id',
        'machine_model_id',
        'images',
        'creator_id',
        'updater_id',
    ];

    protected $appends = ['image_urls', 'calculated_status'];

    /**
     * 動態計算機台當前狀態
     * 1. 離線 (offline)：超過 30 秒未收到心跳
     * 2. 異常 (error)：在線但過去 15 分鐘內有錯誤/警告日誌
     * 3. 在線 (online)：正常在線
     */
    public function getCalculatedStatusAttribute(): string
    {
        // 判定離線
        if (!$this->last_heartbeat_at || $this->last_heartbeat_at->diffInSeconds(now()) >= 30) {
            return 'offline';
        }

        // 判定異常 (檢查過去 15 分鐘內是否有 error 或 warning 日誌)
        $hasRecentErrors = $this->logs()
            ->whereIn('level', ['error', 'warning'])
            ->where('created_at', '>=', now()->subMinutes(15))
            ->exists();

        if ($hasRecentErrors) {
            return 'error';
        }

        return 'online';
    }

    /**
     * Scope: 判定在線 (30 秒內有心跳)
     */
    public function scopeOnline($query)
    {
        return $query->where('last_heartbeat_at', '>=', now()->subSeconds(30));
    }

    /**
     * Scope: 判定離線 (超過 30 秒未收到心跳或從未收到心跳)
     */
    public function scopeOffline($query)
    {
        return $query->where(function ($q) {
            $q->whereNull('last_heartbeat_at')
                ->orWhere('last_heartbeat_at', '<', now()->subSeconds(30));
        });
    }

    /**
     * Scope: 判定異常 (過去 15 分鐘內有錯誤或警告日誌)
     */
    public function scopeHasError($query)
    {
        return $query->whereExists(function ($q) {
            $q->select(\Illuminate\Support\Facades\DB::raw(1))
                ->from('machine_logs')
                ->whereColumn('machine_logs.machine_id', 'machines.id')
                ->whereIn('level', ['error', 'warning'])
                ->where('created_at', '>=', now()->subMinutes(15));
        });
    }

    /**
     * Scope: 判定運行中 (在線且無近期異常)
     */
    public function scopeRunning($query)
    {
        return $query->online()->whereNotExists(function ($q) {
            $q->select(\Illuminate\Support\Facades\DB::raw(1))
                ->from('machine_logs')
                ->whereColumn('machine_logs.machine_id', 'machines.id')
                ->whereIn('level', ['error', 'warning'])
                ->where('created_at', '>=', now()->subMinutes(15));
        });
    }

    /**
     * Scope: 判定異常在線 (在線且有近期異常)
     */
    public function scopeErrorOnline($query)
    {
        return $query->online()->hasError();
    }

    protected $casts = [
        'last_heartbeat_at' => 'datetime',
        'welcome_gift_enabled' => 'boolean',
        'is_spring_slot_1_10' => 'boolean',
        'is_spring_slot_11_20' => 'boolean',
        'is_spring_slot_21_30' => 'boolean',
        'is_spring_slot_31_40' => 'boolean',
        'is_spring_slot_41_50' => 'boolean',
        'is_spring_slot_51_60' => 'boolean',
        'member_system_enabled' => 'boolean',
        'images' => 'array',
    ];

    /**
     * Get machine images absolute URLs
     */
    public function getImageUrlsAttribute(): array
    {
        if (empty($this->images)) {
            return [];
        }

        return array_map(fn($path) => \Illuminate\Support\Facades\Storage::disk('public')->url($path), $this->images);
    }

    public function logs()
    {
        return $this->hasMany(MachineLog::class);
    }

    public function slots()
    {
        return $this->hasMany(MachineSlot::class);
    }

    public function commands()
    {
        return $this->hasMany(RemoteCommand::class);
    }

    public function machineModel()
    {
        return $this->belongsTo(MachineModel::class);
    }

    public function paymentConfig()
    {
        return $this->belongsTo(\App\Models\System\PaymentConfig::class);
    }

    public function creator()
    {
        return $this->belongsTo(\App\Models\System\User::class, 'creator_id');
    }

    public function updater()
    {
        return $this->belongsTo(\App\Models\System\User::class, 'updater_id');
    }

    public const PAGE_STATUSES = [
        '0' => 'Offline',
        '1' => 'Home Page',
        '2' => 'Vending Page',
        '3' => 'Admin Page',
        '4' => 'Replenishment Page',
        '5' => 'Tutorial Page',
        '6' => 'Purchasing',
        '7' => 'Locked Page',
        '60' => 'Dispense Success',
        '61' => 'Slot Test',
        '62' => 'Payment Selection',
        '63' => 'Waiting for Payment',
        '64' => 'Dispensing',
        '65' => 'Receipt Printing',
        '66' => 'Pass Code',
        '67' => 'Pickup Code',
        '68' => 'Message Display',
        '69' => 'Cancel Purchase',
        '610' => 'Purchase Finished',
        '611' => 'Welcome Gift',
        '612' => 'Dispense Failed',
    ];

    public function getCurrentPageLabelAttribute(): string
    {
        $code = (string) $this->current_page;
        $label = self::PAGE_STATUSES[$code] ?? $code;
        return __($label);
    }

    public function users()
    {
        return $this->belongsToMany(\App\Models\System\User::class);
    }
}
