<?php

namespace App\Models;

use App\Enums\ConsultationStatus;
use App\Enums\ConsultationType;
use App\Enums\PaymentStatus;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;

class Consultation extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'guest_name',
        'guest_email',
        'guest_phone',
        'booking_date',
        'booking_time',
        'problem_summary',
        'consultation_type',
        'payment_amount',
        'payment_status',
        'payment_received_at',
        'status',
        'admin_notes',
        'reminder_24h_sent_at',
        'reminder_2h_sent_at',
    ];

    protected function casts(): array
    {
        return [
            'booking_date' => 'date',
            'consultation_type' => ConsultationType::class,
            'payment_status' => PaymentStatus::class,
            'status' => ConsultationStatus::class,
            'payment_amount' => 'decimal:2',
            'payment_received_at' => 'datetime',
            'admin_notes' => 'array',
            'reminder_24h_sent_at' => 'datetime',
            'reminder_2h_sent_at' => 'datetime',
        ];
    }

    protected static function booted(): void
    {
        static::saving(function (Consultation $consultation) {
            // Either user_id or guest fields must be present
            if (is_null($consultation->user_id)) {
                if (empty($consultation->guest_name) ||
                    empty($consultation->guest_email) ||
                    empty($consultation->guest_phone)) {
                    throw new \InvalidArgumentException(
                        'Guest consultations require guest_name, guest_email, and guest_phone'
                    );
                }
            }
        });
    }

    /**
     * Get the user that owns the consultation.
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Check if this is a guest consultation (no linked user).
     */
    public function isGuest(): bool
    {
        return is_null($this->user_id);
    }

    /**
     * Get the client's display name.
     */
    public function getClientName(): string
    {
        return $this->isGuest()
            ? $this->guest_name
            : $this->user->full_name;
    }

    /**
     * Get the client's email address.
     */
    public function getClientEmail(): string
    {
        return $this->isGuest()
            ? $this->guest_email
            : $this->user->email;
    }

    /**
     * Get the client's phone number.
     */
    public function getClientPhone(): ?string
    {
        return $this->isGuest()
            ? $this->guest_phone
            : $this->user->phone;
    }

    /**
     * Mark consultation as completed.
     *
     * @throws \InvalidArgumentException
     */
    public function markAsCompleted(): void
    {
        if ($this->status !== ConsultationStatus::Approved) {
            throw new \InvalidArgumentException(
                __('messages.invalid_status_transition', ['from' => $this->status->value, 'to' => 'completed'])
            );
        }
        $this->update(['status' => ConsultationStatus::Completed]);
    }

    /**
     * Mark consultation as no-show.
     *
     * @throws \InvalidArgumentException
     */
    public function markAsNoShow(): void
    {
        if ($this->status !== ConsultationStatus::Approved) {
            throw new \InvalidArgumentException(
                __('messages.invalid_status_transition', ['from' => $this->status->value, 'to' => 'no_show'])
            );
        }
        $this->update(['status' => ConsultationStatus::NoShow]);
    }

    /**
     * Cancel the consultation.
     *
     * @throws \InvalidArgumentException
     */
    public function cancel(): void
    {
        if (! in_array($this->status, [ConsultationStatus::Pending, ConsultationStatus::Approved])) {
            throw new \InvalidArgumentException(
                __('messages.cannot_cancel_consultation')
            );
        }
        $this->update(['status' => ConsultationStatus::Cancelled]);
    }

    /**
     * Mark payment as received.
     *
     * @throws \InvalidArgumentException
     */
    public function markPaymentReceived(): void
    {
        if ($this->consultation_type !== ConsultationType::Paid) {
            throw new \InvalidArgumentException(__('messages.not_paid_consultation'));
        }
        if ($this->payment_status === PaymentStatus::Received) {
            throw new \InvalidArgumentException(__('messages.payment_already_received'));
        }
        $this->update([
            'payment_status' => PaymentStatus::Received,
            'payment_received_at' => now(),
        ]);
    }

    /**
     * Reschedule the consultation to a new date and time.
     */
    public function reschedule(string $newDate, string $newTime): void
    {
        $this->update([
            'booking_date' => $newDate,
            'booking_time' => $newTime,
        ]);
    }

    /**
     * Add an admin note to the consultation.
     */
    public function addNote(string $note, int $adminId): void
    {
        $notes = $this->admin_notes ?? [];
        $notes[] = [
            'text' => $note,
            'admin_id' => $adminId,
            'created_at' => now()->toISOString(),
        ];
        $this->update(['admin_notes' => $notes]);
    }

    /**
     * Update an admin note at the given index.
     */
    public function updateNote(int $index, string $newText): void
    {
        $notes = $this->admin_notes ?? [];
        if (isset($notes[$index])) {
            $notes[$index]['text'] = $newText;
            $notes[$index]['updated_at'] = now()->toISOString();
            $this->update(['admin_notes' => $notes]);
        }
    }

    /**
     * Delete an admin note at the given index.
     */
    public function deleteNote(int $index): void
    {
        $notes = $this->admin_notes ?? [];
        if (isset($notes[$index])) {
            array_splice($notes, $index, 1);
            $this->update(['admin_notes' => array_values($notes)]);
        }
    }

    /**
     * Scope for pending consultations.
     */
    public function scopePending(Builder $query): Builder
    {
        return $query->where('status', ConsultationStatus::Pending);
    }

    /**
     * Scope for approved consultations.
     */
    public function scopeApproved(Builder $query): Builder
    {
        return $query->where('status', ConsultationStatus::Approved);
    }

    /**
     * Scope for upcoming approved consultations.
     */
    public function scopeUpcoming(Builder $query): Builder
    {
        return $query->where('booking_date', '>=', today())
            ->where('status', ConsultationStatus::Approved);
    }

    /**
     * Scope for past consultations.
     */
    public function scopePast(Builder $query): Builder
    {
        return $query->where(function ($q) {
            $q->where('booking_date', '<', today())
                ->orWhereIn('status', [
                    ConsultationStatus::Completed,
                    ConsultationStatus::Cancelled,
                    ConsultationStatus::NoShow,
                ]);
        });
    }

    /**
     * Scope for guest consultations (no linked user).
     */
    public function scopeGuests(Builder $query): Builder
    {
        return $query->whereNull('user_id');
    }

    /**
     * Scope for client consultations (has linked user).
     */
    public function scopeClients(Builder $query): Builder
    {
        return $query->whereNotNull('user_id');
    }
}
