<?php

namespace App\Models;

use App\Models\Traits\HasAuditFields;
use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;

class Machines extends Model
{
    use HasFactory, SoftDeletes, HasAuditFields;

    protected $table = 'machines';

    /**
     * Status constants
     */
    public const STATUS_ACTIVE = 'active';
    public const STATUS_INACTIVE = 'inactive';
    public const STATUS_BREAKDOWN = 'breakdown';
    public const STATUS_MAINTENANCE = 'maintenance';

    protected $fillable = [
        'machine_id',
        'machine_code',
        'machine_name',
        'machine_sl_no',
        'make',
        'model_type',
        'diameter',
        'length',
        'weight',
        'remarks',
        'status',
        'is_running',
        'started_at',
        'stopped_at',
        'created_by',
        'updated_by',
    ];

    protected $casts = [
        'is_running' => 'boolean',
        'started_at' => 'datetime',
        'stopped_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    protected $attributes = [
        'status' => self::STATUS_ACTIVE,
        'is_running' => false,
    ];

    protected $appends = ['availability', 'available_by'];

    // ──────────────────────────────────────────────────────────────────────────
    // RELATIONSHIPS
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Get processes this machine is assigned to
     */
    public function processes()
    {
        return $this->belongsToMany(Process::class, 'process_machine', 'machine_id', 'process_id')
            ->withTimestamps();
    }

    /**
     * Get route card processes using this machine
     */
    public function routeCardProcesses()
    {
        return $this->hasMany(RouteCardProcess::class, 'machine', 'id');
    }

    /**
     * Get operators assigned to this machine
     */
    public function operators()
    {
        return $this->belongsToMany(EmployeeDetails::class, 'machine_operator', 'machine_id', 'employee_id')
            ->withTimestamps();
    }

    /**
     * Get machine logs
     */
    public function logs()
    {
        return $this->hasMany(MachineLog::class, 'machine_id');
    }

    // ──────────────────────────────────────────────────────────────────────────
    // SCOPES
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Filter by active status
     */
    public function scopeActive(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_ACTIVE);
    }

    /**
     * Filter available machines (active and not running)
     */
    public function scopeAvailable(Builder $query): Builder
    {
        return $query->where('status', self::STATUS_ACTIVE)
            ->where('is_running', false);
    }

    /**
     * Filter running machines
     */
    public function scopeRunning(Builder $query): Builder
    {
        return $query->where('is_running', true);
    }

    /**
     * Search by name or code
     */
    public function scopeSearch(Builder $query, string $term): Builder
    {
        return $query->where(function ($q) use ($term) {
            $q->where('machine_name', 'like', "%{$term}%")
                ->orWhere('machine_code', 'like', "%{$term}%")
                ->orWhere('machine_id', 'like', "%{$term}%");
        });
    }

    /**
     * Order by name
     */
    public function scopeOrderByName(Builder $query): Builder
    {
        return $query->orderBy('machine_name', 'asc');
    }

    // ──────────────────────────────────────────────────────────────────────────
    // ACCESSORS
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Get machine availability status
     */
    public function getAvailabilityAttribute(): int
    {
        return $this->checkAvailability();
    }

    public function checkAvailability(?Carbon $referenceDate = null): int
    {
        $now = $referenceDate ?? Carbon::now();
        $startTime = $now->copy()->startOfDay();
        $endTime = $now->copy()->endOfDay();

        $inUse = $this->routeCardProcesses()
            ->where(function ($query) use ($startTime, $endTime) {
                $query->where(function ($q) use ($startTime, $endTime) {
                    $q->where('start_date', '<=', $startTime)
                        ->where('end_date', '>=', $endTime);
                })->orWhere(function ($q) use ($startTime) {
                    $q->where('start_date', '>=', $startTime);
                })->orWhere(function ($q) use ($startTime) {
                    $q->where('end_date', '<=', $startTime);
                });
            })
            ->exists();

        return $inUse ? 0 : 1;
    }

    /**
     * Get next available time
     */
    public function getAvailableByAttribute(): string
    {
        return $this->getNextAvailability();
    }

    public function getNextAvailability(?Carbon $referenceDate = null): string
    {
        $now = $referenceDate ?? Carbon::now();
        $startTime = $now->copy()->startOfDay();
        $endTime = $now->copy()->endOfDay();

        $nextAvailability = $this->routeCardProcesses()
            ->where(function ($query) use ($startTime, $endTime) {
                $query->where(function ($q) use ($startTime, $endTime) {
                    $q->where('start_date', '<=', $startTime)
                        ->where('end_date', '>=', $endTime);
                })->orWhere(function ($q) use ($startTime) {
                    $q->where('start_date', '>=', $startTime);
                })->orWhere(function ($q) use ($startTime) {
                    $q->where('end_date', '<=', $startTime);
                });
            })
            ->orderBy('end_date', 'desc')
            ->value('end_date');

        return $nextAvailability
            ? Carbon::parse($nextAvailability)->format('Y-m-d H:i')
            : Carbon::parse($now)->format('Y-m-d H:i');
    }

    // ──────────────────────────────────────────────────────────────────────────
    // HELPERS
    // ──────────────────────────────────────────────────────────────────────────

    /**
     * Get all valid statuses
     */
    public static function getStatuses(): array
    {
        return [
            self::STATUS_ACTIVE,
            self::STATUS_INACTIVE,
            self::STATUS_BREAKDOWN,
            self::STATUS_MAINTENANCE,
        ];
    }

    /**
     * Check if machine is active
     */
    public function isActive(): bool
    {
        return $this->status === self::STATUS_ACTIVE;
    }

    /**
     * Check if machine is currently running
     */
    public function isRunning(): bool
    {
        return (bool) $this->is_running;
    }

    /**
     * Check if machine is available for use
     */
    public function isAvailable(): bool
    {
        return $this->isActive() && !$this->isRunning() && $this->availability === 1;
    }
}
