<?php

use App\Models\Invitation;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;

uses(RefreshDatabase::class);

describe('Invitation Model', function () {
    
    it('can create an invitation', function () {
        $user = User::factory()->create();
        
        $invitation = Invitation::create([
            'code' => 'test-invitation-code',
            'email' => 'test@example.com',
            'invited_by' => $user->id,
            'expires_at' => now()->addDays(7)
        ]);

        expect($invitation->code)->toBe('test-invitation-code');
        expect($invitation->email)->toBe('test@example.com');
        expect($invitation->invited_by)->toBe($user->id);
    });

    it('has status method that returns correct status', function () {
        $invitation = Invitation::factory()->create(['accepted_at' => null]);
        expect($invitation->status())->toBe('pending');

        $invitation->update(['accepted_at' => now()]);
        expect($invitation->status())->toBe('accepted');
    });

    it('has isPending method that checks if invitation is pending', function () {
        $invitation = Invitation::factory()->create(['accepted_at' => null]);
        expect($invitation->isPending())->toBe(true);

        $invitation->update(['accepted_at' => now()]);
        expect($invitation->isPending())->toBe(false);
    });

    it('can accept an invitation', function () {
        $invitation = Invitation::factory()->create(['accepted_at' => null]);
        
        expect($invitation->isPending())->toBe(true);
        
        $invitation->accept();
        
        expect($invitation->isPending())->toBe(false);
        expect($invitation->accepted_at)->not()->toBeNull();
        expect($invitation->status())->toBe('accepted');
    });

    it('belongs to a creator user', function () {
        $creator = User::factory()->create();
        $invitation = Invitation::factory()->create(['invited_by' => $creator->id]);

        expect($invitation->creator)->toBeInstanceOf(User::class);
        expect($invitation->creator->id)->toBe($creator->id);
    });

    it('generates invite URL correctly', function () {
        $invitation = Invitation::factory()->create(['code' => 'test-code-123']);
        
        $expectedUrl = route('register', ['code' => 'test-code-123']);
        expect($invitation->getInviteUrl())->toBe($expectedUrl);
    });

    it('casts dates properly', function () {
        $invitation = Invitation::factory()->create([
            'expires_at' => '2024-01-01 12:00:00',
            'accepted_at' => '2024-01-01 13:00:00'
        ]);

        expect($invitation->expires_at)->toBeInstanceOf(\Illuminate\Support\Carbon::class);
        expect($invitation->accepted_at)->toBeInstanceOf(\Illuminate\Support\Carbon::class);
    });

    it('has fillable fields except id', function () {
        $invitation = new Invitation();
        
        expect($invitation->getFillable())->not()->toContain('id');
        // Since guarded is used with ['id'], all other fields should be fillable
        expect($invitation->getGuarded())->toBe(['id']);
    });

    it('uses HasFactory trait', function () {
        expect(method_exists(Invitation::class, 'factory'))->toBe(true);
        expect(in_array('Illuminate\Database\Eloquent\Factories\HasFactory', class_uses(Invitation::class)))->toBe(true);
    });

    it('can find invitation by code', function () {
        $invitation = Invitation::factory()->create(['code' => 'unique-code-456']);
        
        $found = Invitation::where('code', 'unique-code-456')->first();
        
        expect($found)->not()->toBeNull();
        expect($found->id)->toBe($invitation->id);
    });

    it('can find invitation by email', function () {
        $invitation = Invitation::factory()->create(['email' => 'unique@test.com']);
        
        $found = Invitation::where('email', 'unique@test.com')->first();
        
        expect($found)->not()->toBeNull();
        expect($found->id)->toBe($invitation->id);
    });

    it('can filter pending invitations', function () {
        $pendingInvitation = Invitation::factory()->create(['accepted_at' => null]);
        $acceptedInvitation = Invitation::factory()->create(['accepted_at' => now()]);
        
        $pending = Invitation::whereNull('accepted_at')->get();
        
        expect($pending->count())->toBe(1);
        expect($pending->first()->id)->toBe($pendingInvitation->id);
    });

    it('can filter accepted invitations', function () {
        $pendingInvitation = Invitation::factory()->create(['accepted_at' => null]);
        $acceptedInvitation = Invitation::factory()->create(['accepted_at' => now()]);
        
        $accepted = Invitation::whereNotNull('accepted_at')->get();
        
        expect($accepted->count())->toBe(1);
        expect($accepted->first()->id)->toBe($acceptedInvitation->id);
    });

    it('accept method persists to database', function () {
        $invitation = Invitation::factory()->create(['accepted_at' => null]);
        
        $invitation->accept();
        
        // Refresh from database to verify it was persisted
        $invitation->refresh();
        
        expect($invitation->accepted_at)->not()->toBeNull();
        expect($invitation->isPending())->toBe(false);
    });
});