<?php

namespace App\Models;

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

class OrderCourierShipment extends Model
{
    use HasFactory;

    protected $guarded = [];

    protected $casts = [
        'collectable_amount' => 'float',
        'customer_delivery_charge' => 'float',
        'cod_collected_amount' => 'float',
        'actual_delivery_cost' => 'float',
        'actual_return_cost' => 'float',
        'actual_cod_charge' => 'float',
        'settled_amount' => 'float',
        'net_receivable_amount' => 'float',
        'net_received_amount' => 'float',
        'balance_amount' => 'float',
        'request_payload' => 'array',
        'response_payload' => 'array',
        'settlement_payload' => 'array',
        'cod_collected_at' => 'datetime',
        'delivered_at' => 'datetime',
        'sent_to_courier_at' => 'datetime',
        'courier_synced_at' => 'datetime',
        'out_for_delivery_at' => 'datetime',
        'out_for_delivery_sms_sent_at' => 'datetime',
        'out_for_delivery_sms_last_attempt_at' => 'datetime',
        'out_for_delivery_sms_next_retry_at' => 'datetime',
        'out_for_delivery_sms_attempts' => 'integer',
        'cod_received_at' => 'datetime',
        'settlement_paid_at' => 'datetime',
        'courier_accounting_synced_at' => 'datetime',
        'created_at' => 'datetime',
        'updated_at' => 'datetime',
    ];

    public function codReceivedBy()
    {
        return $this->belongsTo(Admin::class, 'cod_received_by_admin_id');
    }

    public function isCodReceived(): bool
    {
        return $this->cod_received_at !== null;
    }

    public function isCodPending(): bool
    {
        return $this->collectable_amount > 0 && $this->cod_received_at === null;
    }

    public function order()
    {
        return $this->belongsTo(Order::class);
    }

    public function courier()
    {
        return $this->belongsTo(Courier::class);
    }

    public function ledgerEntries()
    {
        return $this->hasMany(CourierLedgerEntry::class, 'order_courier_shipment_id')->latest('entry_date')->latest('id');
    }

    public function settlementItems()
    {
        return $this->hasMany(CourierSettlementItem::class, 'order_courier_shipment_id');
    }

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

    public function statusEvents()
    {
        return $this->hasMany(CourierStatusEvent::class);
    }

    public function hasConfirmedCourierRider(): bool
    {
        return filled($this->courier_rider_id)
            || filled($this->courier_rider_name)
            || filled($this->courier_rider_phone);
    }

    public function isCourierConfirmedOutForDelivery(): bool
    {
        return $this->status_mapping_result === 'out_for_delivery'
            && $this->out_for_delivery_at !== null
            && $this->hasConfirmedCourierRider();
    }

    public function customerTrackingData(): array
    {
        return [
            'provider' => $this->provider,
            'booking_status' => $this->booking_status,
            'courier_status' => $this->courier_status,
            'courier_status_code' => $this->courier_status_code,
            'courier_status_text' => $this->courier_status_text,
            'rider_id' => $this->courier_rider_id,
            'rider_name' => $this->courier_rider_name,
            'rider_phone' => $this->courier_rider_phone,
            'event_reference' => $this->courier_event_reference,
            'out_for_delivery_at' => $this->out_for_delivery_at,
            'out_for_delivery_confirmed' => $this->isCourierConfirmedOutForDelivery(),
            'courier_parcel_id' => $this->courier_parcel_id,
            'courier_tracking_id' => $this->courier_tracking_id,
            'courier_consignment_id' => $this->courier_consignment_id,
            'sent_to_courier_at' => $this->sent_to_courier_at,
            'courier_synced_at' => $this->courier_synced_at,
        ];
    }

    public function sentByAdmin()
    {
        return $this->belongsTo(Admin::class, 'sent_by_admin_id');
    }

    public function lastSyncedByAdmin()
    {
        return $this->belongsTo(Admin::class, 'last_synced_by_admin_id');
    }

    public function hasSuccessfulBooking(): bool
    {
        return $this->booking_status === 'booked' && filled($this->courier_parcel_id);
    }

    public function canRetry(): bool
    {
        return in_array($this->booking_status, ['not_sent', 'failed'], true);
    }
}
