<?php

namespace App\Models;

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

class EmailDeliveryLog extends Model
{
    public const STATUS_PENDING = 'pending';

    public const STATUS_SENT = 'sent';

    public const STATUS_DELIVERED = 'delivered';

    public const STATUS_OPENED = 'opened';

    public const STATUS_CLICKED = 'clicked';

    public const STATUS_UNSUBSCRIBED = 'unsubscribed';

    public const STATUS_BOUNCED = 'bounced';

    public const STATUS_FAILED = 'failed';

    public const TYPE_JOB_ALERT = 'job_alert';

    public const TYPE_APPLICATION_FOLLOW_UP = 'application_follow_up';

    public const TYPE_PASSWORD_RESET_OTP = 'password_reset_otp';

    protected $fillable = [
        'user_id',
        'type',
        'provider',
        'provider_message_id',
        'brevo_message_id',
        'recipient_email',
        'recipient_name',
        'subject',
        'status',
        'resendable',
        'headers',
        'metadata',
        'event_counts',
        'sent_at',
        'delivered_at',
        'opened_at',
        'clicked_at',
        'unsubscribed_at',
        'bounced_at',
        'failed_at',
        'failure_reason',
    ];

    /**
     * @return BelongsTo<User, $this>
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function canBeResent(): bool
    {
        return $this->status === self::STATUS_FAILED && $this->resendable;
    }

    public function markEvent(string $event, ?string $occurredAt = null): void
    {
        $timestamp = $occurredAt ? rescue(fn () => \Illuminate\Support\Carbon::parse($occurredAt), now(), report: false) : now();
        $counts = $this->event_counts ?: [];
        $counts[$event] = ((int) ($counts[$event] ?? 0)) + 1;

        $updates = [
            'event_counts' => $counts,
        ];

        match ($event) {
            'delivered' => $updates += ['status' => self::STATUS_DELIVERED, 'delivered_at' => $this->delivered_at ?: $timestamp],
            'opened' => $updates += ['status' => self::STATUS_OPENED, 'opened_at' => $this->opened_at ?: $timestamp],
            'clicked' => $updates += ['status' => self::STATUS_CLICKED, 'clicked_at' => $this->clicked_at ?: $timestamp],
            'unsubscribed' => $updates += ['status' => self::STATUS_UNSUBSCRIBED, 'unsubscribed_at' => $this->unsubscribed_at ?: $timestamp],
            'bounced' => $updates += ['status' => self::STATUS_BOUNCED, 'bounced_at' => $this->bounced_at ?: $timestamp],
            'failed' => $updates += ['status' => self::STATUS_FAILED, 'failed_at' => $this->failed_at ?: $timestamp],
            default => null,
        };

        $this->forceFill($updates)->save();
    }

    /**
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'resendable' => 'boolean',
            'headers' => 'array',
            'metadata' => 'array',
            'event_counts' => 'array',
            'sent_at' => 'datetime',
            'delivered_at' => 'datetime',
            'opened_at' => 'datetime',
            'clicked_at' => 'datetime',
            'unsubscribed_at' => 'datetime',
            'bounced_at' => 'datetime',
            'failed_at' => 'datetime',
        ];
    }
}
