<?php

namespace App\Models;

use App\Enums\UserRole;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;

class User extends Authenticatable
{
    use HasFactory, Notifiable, HasApiTokens, SoftDeletes;

    /**
     * The attributes that are mass assignable.
     *
     * @var list<string>
     */
    protected $fillable = [
        'name',
        'username',
        'email',
        'phone',
        'google_id',
        'apple_id',
        'password',
        'role',
        'avatar',
        'bio',
        'is_active',
        'phone_verified_at',
        'phone_verification_code',
        'phone_verification_expires_at',
        'phone_verification_attempts',
        'notifications_enabled',
        'captain_agreement_accepted_at',
        'province_id',
        'city_id',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var list<string>
     */
    protected $hidden = [
        'password',
        'remember_token',
        'phone_verification_code',
        'phone_verification_expires_at',
        'phone_verification_attempts',
    ];

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'phone_verified_at' => 'datetime',
            'phone_verification_expires_at' => 'datetime',
            'password' => 'hashed',
            'role' => UserRole::class,
            'is_active' => 'boolean',
            'notifications_enabled' => 'boolean',
            'captain_agreement_accepted_at' => 'datetime',
        ];
    }

    /**
     * User's listings (for boat owners)
     */
    public function province(): BelongsTo
    {
        return $this->belongsTo(Province::class);
    }

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

    public function listings(): HasMany
    {
        return $this->hasMany(Listing::class);
    }

    /**
     * User's reservations (for customers)
     */
    public function reservations(): HasMany
    {
        return $this->hasMany(Reservation::class);
    }

    /**
     * User's device tokens for push notifications
     */
    public function devices()
    {
        return $this->hasMany(DeviceToken::class);
    }

    public function deviceTokens()
    {
        return $this->devices();
    }

    public function conversations()
    {
        return $this->belongsToMany(Conversation::class);
    }

    /**
     * Check if user is admin
     */
    public function isAdmin(): bool
    {
        return $this->role === UserRole::ADMIN;
    }

    /**
     * Check if user is boat owner
     */
    public function isBoatOwner(): bool
    {
        return $this->role === UserRole::BOAT_OWNER;
    }

    /**
     * Check if user is customer
     */
    /**
     * User's favorite listings
     */
    public function favoriteListings(): HasMany
    {
        return $this->hasMany(FavoriteListing::class);
    }

    /**
     * Check if user has favorited a listing
     */
    public function hasFavorited(int $listingId): bool
    {
        return $this->favoriteListings()->where('listing_id', $listingId)->exists();
    }

    public function reviewsReceived(): HasMany
    {
        return $this->hasMany(CaptainReview::class, 'captain_id');
    }

    public function reviewsGiven(): HasMany
    {
        return $this->hasMany(CaptainReview::class, 'user_id');
    }

    public function followers(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'follows', 'following_id', 'follower_id')
                    ->withPivot('created_at');
    }

    public function following(): BelongsToMany
    {
        return $this->belongsToMany(User::class, 'follows', 'follower_id', 'following_id')
                    ->withPivot('created_at');
    }

    public function posts(): HasMany
    {
        return $this->hasMany(Post::class);
    }

    public function store(): HasOne
    {
        return $this->hasOne(Store::class);
    }

    public function hasStore(): bool
    {
        return $this->store()->exists();
    }

    public function stockAlerts(): HasMany
    {
        return $this->hasMany(StockAlert::class);
    }

    public function isFollowing(int $userId): bool
    {
        return $this->following()->where('following_id', $userId)->exists();
    }

    protected $appends = ['has_password'];

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

    private static array $turkishMap = [
        'ı' => 'i', 'ğ' => 'g', 'ü' => 'u', 'ş' => 's', 'ö' => 'o', 'ç' => 'c',
        'İ' => 'i', 'Ğ' => 'g', 'Ü' => 'u', 'Ş' => 's', 'Ö' => 'o', 'Ç' => 'c',
    ];

    private static array $reservedUsernames = [
        'admin', 'login', 'register', 'api', 'listings', 'help', 'settings',
        'profile', 'home', 'about', 'contact', 'privacy', 'terms', 'support',
        'captains', 'owner', 'chat', 'notifications', 'favorites', 'reservations',
        'search', 'explore', 'kaptango', 'www', 'mail', 'blog', 'app',
    ];

    public static function generateUsername(string $name): string
    {
        $base = strtr($name, self::$turkishMap);
        $base = mb_strtolower($base);
        $base = preg_replace('/[^a-z0-9]/', '', $base);

        if (strlen($base) < 3) {
            $base = 'user' . $base;
        }

        if (in_array($base, self::$reservedUsernames, true)) {
            $base .= random_int(100, 999);
        }

        $candidate = $base;
        while (self::where('username', $candidate)->exists()) {
            $candidate = $base . random_int(100, 999);
        }

        return $candidate;
    }
}
