<?php

namespace Tests\Feature;

use App\Models\ProjectCharter;
use App\Models\ProjectCharterChangeRequest;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Auth;
use Tests\TestCase;

class ProjectCharterChangeRequestTwoStageApprovalTest extends TestCase
{
    use RefreshDatabase, WithFaker;

    protected User $user;

    protected User $firstApprover;

    protected User $finalApprover;

    protected ProjectCharter $projectCharter;

    protected ProjectCharterChangeRequest $changeRequest;

    protected function setUp(): void
    {
        parent::setUp();

        // Create test users
        $this->user = User::factory()->create();
        $this->firstApprover = User::factory()->create();
        $this->finalApprover = User::factory()->create();

        // Create project charter
        $this->projectCharter = ProjectCharter::factory()->create();

        // Create change request
        $this->changeRequest = ProjectCharterChangeRequest::factory()->create([
            'project_charter_id' => $this->projectCharter->id,
            'requested_by' => $this->user->id,
            'status' => ProjectCharterChangeRequest::STATUS_PENDING,
            'change_type' => ProjectCharterChangeRequest::CHANGE_TYPE_SCOPE,
            'justification' => 'Test justification',
            'scope_changes' => 'Test scope changes',
        ]);
    }

    public function test_change_request_can_be_first_approved(): void
    {
        // Grant permissions (we'll skip actual permission checking in this test)
        Auth::login($this->firstApprover);

        $result = $this->changeRequest->firstApprove('First approval notes');

        $this->assertTrue($result);
        $this->assertEquals(ProjectCharterChangeRequest::STATUS_FIRST_APPROVED, $this->changeRequest->status);
        $this->assertEquals($this->firstApprover->id, $this->changeRequest->first_approved_by);
        $this->assertEquals('First approval notes', $this->changeRequest->first_approval_notes);
        $this->assertNotNull($this->changeRequest->first_approved_at);
    }

    public function test_change_request_can_be_final_approved_after_first_approval(): void
    {
        // First, do the first approval
        Auth::login($this->firstApprover);
        $this->firstApprover->shouldReceive('can')
            ->with('approve_change_request_project::charter::change::request')
            ->andReturn(true);
        $this->changeRequest->firstApprove('First approval notes');

        // Now do the final approval
        Auth::login($this->finalApprover);
        $this->finalApprover->shouldReceive('can')
            ->with('final_approve_change_request_project::charter::change::request')
            ->andReturn(true);

        $result = $this->changeRequest->finalApprove('Final approval notes');

        $this->assertTrue($result);
        $this->assertEquals(ProjectCharterChangeRequest::STATUS_APPROVED, $this->changeRequest->status);
        $this->assertEquals($this->finalApprover->id, $this->changeRequest->final_approved_by);
        $this->assertEquals('Final approval notes', $this->changeRequest->final_approval_notes);
        $this->assertNotNull($this->changeRequest->final_approved_at);
    }

    public function test_change_request_final_approval_stores_attachment_count_in_activity_log(): void
    {
        // First, do the first approval
        Auth::login($this->firstApprover);
        $this->firstApprover->shouldReceive('can')
            ->with('approve_change_request_project::charter::change::request')
            ->andReturn(true);
        $this->changeRequest->firstApprove('First approval notes');

        // Now do the final approval
        Auth::login($this->finalApprover);
        $this->finalApprover->shouldReceive('can')
            ->with('final_approve_change_request_project::charter::change::request')
            ->andReturn(true);

        $result = $this->changeRequest->finalApprove('Final approval notes');

        $this->assertTrue($result);

        // Check that activity log was created with attachment count
        $this->assertDatabaseHas('activity_log', [
            'subject_id' => $this->changeRequest->id,
            'subject_type' => ProjectCharterChangeRequest::class,
            'event' => 'final_approved',
        ]);

        $activityLog = \Spatie\Activitylog\Models\Activity::where([
            'subject_id' => $this->changeRequest->id,
            'event' => 'final_approved',
        ])->first();

        $this->assertNotNull($activityLog);
        $properties = $activityLog->properties;
        $this->assertArrayHasKey('attachments_count', $properties);
        $this->assertEquals(0, $properties['attachments_count']); // No attachments in this test
    }

    public function test_get_final_approval_attachments_method_works(): void
    {
        $attachments = $this->changeRequest->getFinalApprovalAttachments();
        $this->assertInstanceOf(\Illuminate\Database\Eloquent\Collection::class, $attachments);
        $this->assertEquals(0, $attachments->count()); // No attachments initially
    }

    public function test_change_request_cannot_be_final_approved_without_first_approval(): void
    {
        Auth::login($this->finalApprover);
        $this->finalApprover->shouldReceive('can')
            ->with('final_approve_change_request_project::charter::change::request')
            ->andReturn(true);

        $result = $this->changeRequest->finalApprove('Final approval notes');

        $this->assertFalse($result);
        $this->assertEquals(ProjectCharterChangeRequest::STATUS_PENDING, $this->changeRequest->status);
    }

    public function test_change_request_can_be_rejected_from_pending_status(): void
    {
        Auth::login($this->firstApprover);
        $this->firstApprover->shouldReceive('can')
            ->with('approve_change_request_project::charter::change::request')
            ->andReturn(true);

        $result = $this->changeRequest->reject('Rejection reason');

        $this->assertTrue($result);
        $this->assertEquals(ProjectCharterChangeRequest::STATUS_REJECTED, $this->changeRequest->status);
        $this->assertEquals('Rejection reason', $this->changeRequest->review_notes);
    }

    public function test_change_request_can_be_rejected_from_first_approved_status(): void
    {
        // First approve
        Auth::login($this->firstApprover);
        $this->firstApprover->shouldReceive('can')
            ->with('approve_change_request_project::charter::change::request')
            ->andReturn(true);
        $this->changeRequest->firstApprove('First approval notes');

        // Then reject
        Auth::login($this->finalApprover);
        $this->finalApprover->shouldReceive('can')
            ->with('final_approve_change_request_project::charter::change::request')
            ->andReturn(true);

        $result = $this->changeRequest->reject('Final rejection reason');

        $this->assertTrue($result);
        $this->assertEquals(ProjectCharterChangeRequest::STATUS_REJECTED, $this->changeRequest->status);
        $this->assertEquals('Final rejection reason', $this->changeRequest->review_notes);
    }

    public function test_legacy_approve_method_works_for_pending_status(): void
    {
        Auth::login($this->firstApprover);
        $this->firstApprover->shouldReceive('can')
            ->with('approve_change_request_project::charter::change::request')
            ->andReturn(true);

        $result = $this->changeRequest->approve('Legacy approval');

        $this->assertTrue($result);
        $this->assertEquals(ProjectCharterChangeRequest::STATUS_FIRST_APPROVED, $this->changeRequest->status);
        $this->assertEquals('Legacy approval', $this->changeRequest->first_approval_notes);
    }

    public function test_legacy_approve_method_works_for_first_approved_status(): void
    {
        // First approve
        Auth::login($this->firstApprover);
        $this->firstApprover->shouldReceive('can')
            ->with('approve_change_request_project::charter::change::request')
            ->andReturn(true);
        $this->changeRequest->firstApprove('First approval');

        // Use legacy approve method for final approval
        Auth::login($this->finalApprover);
        $this->finalApprover->shouldReceive('can')
            ->with('final_approve_change_request_project::charter::change::request')
            ->andReturn(true);

        $result = $this->changeRequest->approve('Legacy final approval');

        $this->assertTrue($result);
        $this->assertEquals(ProjectCharterChangeRequest::STATUS_APPROVED, $this->changeRequest->status);
        $this->assertEquals('Legacy final approval', $this->changeRequest->final_approval_notes);
    }
}
