<?php

namespace App\Models;

use App\Notifications\VerifyEmailNotification;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable implements MustVerifyEmail
{
    use HasApiTokens;
    use HasFactory;
    use HasProfilePhoto;
    use Notifiable;
    use TwoFactorAuthenticatable;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'first_name',
        'last_name',
        'username',
        'website',
        'email',
        'password',
        'global_settings',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
        'two_factor_recovery_codes',
        'two_factor_secret',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
        'global_settings'   => 'array',
    ];

    /**
     * The accessors to append to the model's array form.
     *
     * @var array<int, string>
     */
    protected $appends = [
        'profile_photo_url',
    ];

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

    public function emailOtps()
    {
        return $this->hasMany(EmailOtp::class);
    }

    /**
     * Sends both a signed verification link and a 6-digit OTP code in one
     * email, instead of Laravel's stock link-only notification.
     */
    public function sendEmailVerificationNotification(): void
    {
        $this->notify(new VerifyEmailNotification());
    }

    public function getGlobalSettingsAttribute($value)
    {
        $stored = [];
        if ($value) {
            $decoded = is_string($value) ? json_decode($value, true) : $value;
            $stored = is_array($decoded) ? $decoded : [];
        }

        $defaults = [
            'business' => [
                'name'    => '',
                'logo'    => '',
                'address' => '',
            ],
            'email' => [
                'from_name'                => trim($this->first_name . ' ' . $this->last_name),
                'from_email'               => $this->email,
                'reply_to_name'            => trim($this->first_name . ' ' . $this->last_name),
                'reply_to_email'           => $this->email,
                'rate_limit_per_second'    => 15,
                'tracking_enabled'         => true,
                'footer_notice'            => "You're receiving this email because you subscribed to our newsletter.",
                'footer_copyright'         => '© ' . date('Y') . ' Your Company · All rights reserved',
                'footer_show_unsubscribe'  => true,
                'footer_show_privacy'      => true,
                'footer_privacy_url'       => '',
                'unsubscribe_redirect_url' => '',
            ],
            'general' => [
                'timezone' => config('app.timezone') ?: 'UTC',
            ],
        ];

        foreach ($defaults as $section => $fields) {
            if (!isset($stored[$section])) {
                $stored[$section] = $fields;
            } else {
                $stored[$section] = array_merge($fields, array_filter($stored[$section], fn($v) => $v !== null && $v !== ''));
            }
        }

        return $stored;
    }

    protected static function booted(): void
    {
        // Keep `name` (used elsewhere: sidebar initials, activity logs, etc.)
        // in sync whenever first/last name change, so nothing else needs to
        // be updated to know about the new separate fields.
        static::saving(function (User $user) {
            if ($user->isDirty(['first_name', 'last_name'])) {
                $user->name = trim("{$user->first_name} {$user->last_name}") ?: $user->name;
            }
        });
    }
}
