<?php

namespace App\Models;

// use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Database\Factories\UserFactory;
use Illuminate\Database\Eloquent\Attributes\Fillable;
use Illuminate\Database\Eloquent\Attributes\Hidden;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Models\Profile;
use App\Models\Space;
use App\Models\SpaceMember;
use App\Models\Person;
use App\Models\GroupInvitation;

#[Fillable(['name', 'email', 'password', 'is_super_admin'])]
#[Hidden(['password', 'remember_token'])]
class User extends Authenticatable
{
    /** @use HasFactory<UserFactory> */
    use HasFactory, Notifiable;

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

    protected static function booted(): void
    {
        static::created(function (User $user) {
            $configuredSuperAdmins = collect(config('services.super_admin.emails', []))
                ->map(fn ($email) => strtolower(trim((string) $email)))
                ->filter()
                ->values();

            if ($configuredSuperAdmins->contains(strtolower((string) $user->email))) {
                $user->forceFill(['is_super_admin' => true])->saveQuietly();
            }

            DB::transaction(function () use ($user) {
                // Provision default data to match the Supabase trigger behavior.
                $profile = Profile::firstOrCreate(
                    ['user_id' => $user->id],
                    ['display_name' => '', 'avatar' => '🙂']
                );

                $email = strtolower(trim((string) ($user->email ?? '')));

                // If this email was invited to an existing space, join that space instead of creating a new one.
                $inv = $email !== ''
                    ? GroupInvitation::query()
                        ->where('invited_email', $email)
                        ->where('status', 'pending')
                        ->orderBy('created_at', 'desc')
                        ->first()
                    : null;

                if ($inv) {
                    $spaceId = (string) $inv->space_id;

                    // Ensure the user is a member of that space.
                    SpaceMember::query()->firstOrCreate(
                        ['space_id' => $spaceId, 'user_id' => $user->id],
                        ['role' => 'member', 'created_at' => now()]
                    );

                    // Link the pre-created Person (created during invite) to this auth user.
                    $person = Person::query()
                        ->where('space_id', $spaceId)
                        ->where(function ($q) use ($inv, $email) {
                            $q->where('id', (string) $inv->invited_person_id)
                                ->orWhere('email', $email);
                        })
                        ->first();

                    $display = trim($profile->display_name) !== '' ? $profile->display_name : (str($email)->before('@')->toString() ?: 'You');
                    $avatar = trim((string) $profile->avatar) !== '' ? $profile->avatar : '🙂';

                    if ($person) {
                        $person->auth_user_id = $user->id;
                        if (trim((string) $person->name) === '') {
                            $person->name = $display;
                        }
                        if (trim((string) $person->avatar) === '') {
                            $person->avatar = $avatar;
                        }
                        if (trim((string) $person->email) === '' && $email !== '') {
                            $person->email = $email;
                        }
                        $person->save();
                    } else {
                        // Fallback (should be rare): create a person in that space.
                        Person::create([
                            'id' => 'p_' . bin2hex(random_bytes(6)),
                            'space_id' => $spaceId,
                            'auth_user_id' => $user->id,
                            'email' => $email,
                            'name' => $display,
                            'avatar' => $avatar,
                            'created_at' => now(),
                        ]);
                    }

                    // Mark all pending invitations in that space for this email as accepted.
                    GroupInvitation::query()
                        ->where('space_id', $spaceId)
                        ->where('invited_email', $email)
                        ->where('status', 'pending')
                        ->update(['status' => 'accepted']);

                    $profile->default_space_id = $spaceId;
                    $profile->save();
                    return;
                }

                // Default: create a fresh space for the new user.
                $space = Space::create([
                    'id' => (string) Str::uuid(),
                    'name' => 'My space',
                    'created_by' => $user->id,
                ]);

                SpaceMember::create([
                    'space_id' => $space->id,
                    'user_id' => $user->id,
                    'role' => 'owner',
                ]);

                $display = trim($profile->display_name) !== '' ? $profile->display_name : (str($email)->before('@')->toString() ?: 'You');

                Person::create([
                    'id' => (string) $user->id,
                    'space_id' => $space->id,
                    'auth_user_id' => $user->id,
                    'email' => $email,
                    'name' => $display,
                    'avatar' => trim((string) $profile->avatar) !== '' ? $profile->avatar : '🙂',
                ]);

                $profile->default_space_id = $space->id;
                $profile->save();
            });
        });
    }

    /**
     * Get the attributes that should be cast.
     *
     * @return array<string, string>
     */
    protected function casts(): array
    {
        return [
            'email_verified_at' => 'datetime',
            'is_super_admin' => 'boolean',
            'password' => 'hashed',
        ];
    }

    public function isSuperAdmin(): bool
    {
        if ((bool) $this->is_super_admin) {
            return true;
        }

        $configuredSuperAdmins = collect(config('services.super_admin.emails', []))
            ->map(fn ($email) => strtolower(trim((string) $email)))
            ->filter();

        return $configuredSuperAdmins->contains(strtolower((string) $this->email));
    }
}
