<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\HasMany;

class Shipment extends Model
{
    public const STATUSES = [
        'pending' => 'Pending',
        'processing' => 'Processing',
        'picked_up' => 'Picked Up',
        'in_transit' => 'In Transit',
        'at_customs' => 'At Customs',
        'out_for_delivery' => 'Out for Delivery',
        'delivered' => 'Delivered',
        'on_hold' => 'On Hold',
        'returned' => 'Returned',
    ];

    protected $fillable = [
        'tracking_number',
        'service_id',
        'status',
        'current_location',
        'sender_name',
        'sender_email',
        'sender_phone',
        'sender_address',
        'origin_city',
        'origin_country',
        'receiver_name',
        'receiver_email',
        'receiver_phone',
        'receiver_address',
        'destination_city',
        'destination_country',
        'package_description',
        'service_type',
        'delivery_mode',
        'progress_percent',
        'weight_kg',
        'pieces',
        'ship_date',
        'expected_delivery',
        'arrival_at',
        'notes',
        'comment',
        'consignment_no',
    ];

    protected function casts(): array
    {
        return [
            'weight_kg' => 'decimal:2',
            'ship_date' => 'date',
            'expected_delivery' => 'date',
            'arrival_at' => 'datetime',
            'progress_percent' => 'integer',
        ];
    }

    public function service(): BelongsTo
    {
        return $this->belongsTo(Service::class);
    }

    public function events(): HasMany
    {
        return $this->hasMany(ShipmentEvent::class)->orderByDesc('event_at');
    }

    public function statusLabel(): string
    {
        return self::STATUSES[$this->status] ?? ucfirst(str_replace('_', ' ', $this->status));
    }

    public static function generateTrackingNumber(): string
    {
        do {
            $number = 'AEC'.now()->format('y').str_pad((string) random_int(0, 999999), 6, '0', STR_PAD_LEFT);
        } while (self::where('tracking_number', $number)->exists());

        return $number;
    }

    public function progress(): int
    {
        if ($this->progress_percent > 0) {
            return min(100, (int) $this->progress_percent);
        }

        return match ($this->status) {
            'pending' => 8,
            'processing' => 15,
            'picked_up' => 25,
            'in_transit' => 50,
            'at_customs' => 70,
            'out_for_delivery' => 88,
            'delivered' => 100,
            'on_hold' => 40,
            default => 12,
        };
    }

    public function mapQuery(): string
    {
        return $this->current_location ?: trim($this->origin_city.', '.$this->origin_country);
    }

    public function detailLabel(): string
    {
        return match ($this->status) {
            'picked_up' => 'Picked Up',
            'in_transit' => 'Departed',
            'at_customs' => 'At Customs',
            'out_for_delivery' => 'Out for Delivery',
            'delivered' => 'Delivered',
            default => $this->statusLabel(),
        };
    }

    public function parcelStatus(): string
    {
        return match ($this->status) {
            'delivered' => 'Delivered',
            'out_for_delivery' => 'Out for Delivery',
            'at_customs' => 'At Customs',
            'on_hold' => 'On Hold',
            default => 'Parcel Shipped',
        };
    }

    public function arrivalMoment()
    {
        return $this->arrival_at ?: $this->expected_delivery;
    }
}
