<?php

namespace Tests\Feature\Security\Authorization;

use App\Models\Account;
use App\Models\Bank;
use App\Models\Organization;
use App\Models\Tag;
use App\Models\Transaction;
use App\Models\TransactionType;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Livewire\Livewire;
use Namu\WireChat\Models\Conversation;
use Namu\WireChat\Models\Message;
use Tests\TestCase;

/**
 * Export Profile Data Authorization Tests
 *
 * Tests that users can only export their own profile data and cannot export
 * data from profiles they don't own/manage.
 *
 * @group security
 * @group authorization
 * @group export
 * @group critical
 */
class ExportProfileDataAuthorizationTest extends TestCase
{
    use RefreshDatabase;

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

        // Create transaction type for transaction exports
        \DB::table('transaction_types')->insert([
            'id' => 1,
            'name' => 'worked_hours',
            'label' => 'Worked Hours',
            'icon' => 'clock',
        ]);
    }

    /**
     * Test user can export their own transactions
     *
     * @test
     */
    public function user_can_export_own_transactions()
    {
        $user = User::factory()->create();
        $recipient = User::factory()->create();

        $userAccount = Account::factory()->create([
            'accountable_type' => User::class,
            'accountable_id' => $user->id,
        ]);

        $recipientAccount = Account::factory()->create([
            'accountable_type' => User::class,
            'accountable_id' => $recipient->id,
        ]);

        Transaction::factory()->create([
            'from_account_id' => $userAccount->id,
            'to_account_id' => $recipientAccount->id,
            'amount' => 60,
        ]);

        $this->actingAs($user, 'web');
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTransactions', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test user cannot export another user's transactions via session manipulation
     *
     * @test
     */
    public function user_cannot_export_another_users_transactions()
    {
        $user1 = User::factory()->create();
        $user2 = User::factory()->create();

        $user2Account = Account::factory()->create([
            'accountable_type' => User::class,
            'accountable_id' => $user2->id,
        ]);

        // Logged in as user1
        $this->actingAs($user1, 'web');

        // Malicious: manipulate session to target user2
        session(['activeProfileType' => User::class, 'activeProfileId' => $user2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTransactions', 'json');

        $response->assertStatus(403);
    }

    /**
     * Test organization can export own transactions
     *
     * @test
     */
    public function organization_can_export_own_transactions()
    {
        $user = User::factory()->create();
        $organization = Organization::factory()->create();
        $organization->users()->attach($user->id);

        $orgAccount = Account::factory()->create([
            'accountable_type' => Organization::class,
            'accountable_id' => $organization->id,
        ]);

        $this->actingAs($organization, 'organization');
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $organization->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTransactions', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test organization cannot export another organization's transactions
     *
     * @test
     */
    public function organization_cannot_export_another_organizations_transactions()
    {
        $user = User::factory()->create();
        $org1 = Organization::factory()->create();
        $org2 = Organization::factory()->create();
        $org1->users()->attach($user->id);

        // Logged in as both web user and organization
        $this->actingAs($user, 'web');
        $this->actingAs($org1, 'organization');

        // Malicious: manipulate session to target org2
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $org2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTransactions', 'json');

        $response->assertStatus(403);
    }

    /**
     * Test user can export own profile data
     *
     * @test
     */
    public function user_can_export_own_profile_data()
    {
        $user = User::factory()->create();

        $this->actingAs($user, 'web');
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportProfileData', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test user cannot export another user's profile data
     *
     * @test
     */
    public function user_cannot_export_another_users_profile_data()
    {
        $user1 = User::factory()->create();
        $user2 = User::factory()->create();

        // Logged in as user1
        $this->actingAs($user1, 'web');

        // Malicious: manipulate session to target user2
        session(['activeProfileType' => User::class, 'activeProfileId' => $user2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportProfileData', 'json');



        $response->assertStatus(403);
    }

    /**
     * Test user can export own messages
     *
     * @test
     */
    public function user_can_export_own_messages()
    {
        $user = User::factory()->create();
        $recipient = User::factory()->create();

        // Create a conversation using sendMessageTo
        $user->sendMessageTo($recipient, 'Test message');

        $this->actingAs($user, 'web');
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportMessages', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test user cannot export another user's messages
     *
     * @test
     */
    public function user_cannot_export_another_users_messages()
    {
        $user1 = User::factory()->create();
        $user2 = User::factory()->create();
        $recipient = User::factory()->create();

        // Create messages for user2
        $user2->sendMessageTo($recipient, 'User2 private message');

        // Logged in as user1
        $this->actingAs($user1, 'web');

        // Malicious: manipulate session to target user2
        session(['activeProfileType' => User::class, 'activeProfileId' => $user2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportMessages', 'json');



        $response->assertStatus(403);
    }

    /**
     * Test user can export own tags
     *
     * @test
     */
    public function user_can_export_own_tags()
    {
        $user = User::factory()->create();

        // Create a tag and attach to user
        $tag = Tag::factory()->create();
        $user->tags()->attach($tag->id);

        $this->actingAs($user, 'web');
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTags', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test user cannot export another user's tags
     *
     * @test
     */
    public function user_cannot_export_another_users_tags()
    {
        $user1 = User::factory()->create();
        $user2 = User::factory()->create();

        // Create tags for user2
        $tag = Tag::factory()->create();
        $user2->tags()->attach($tag->id);

        // Logged in as user1
        $this->actingAs($user1, 'web');

        // Malicious: manipulate session to target user2
        session(['activeProfileType' => User::class, 'activeProfileId' => $user2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTags', 'json');



        $response->assertStatus(403);
    }

    /**
     * Test user can export own contacts
     *
     * @test
     */
    public function user_can_export_own_contacts()
    {
        $user = User::factory()->create();
        $contact = User::factory()->create();

        // Create a transaction to establish contact
        $userAccount = Account::factory()->create([
            'accountable_type' => User::class,
            'accountable_id' => $user->id,
        ]);

        $contactAccount = Account::factory()->create([
            'accountable_type' => User::class,
            'accountable_id' => $contact->id,
        ]);

        Transaction::factory()->create([
            'from_account_id' => $userAccount->id,
            'to_account_id' => $contactAccount->id,
            'amount' => 60,
        ]);

        $this->actingAs($user, 'web');
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportContacts', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test user cannot export another user's contacts
     *
     * @test
     */
    public function user_cannot_export_another_users_contacts()
    {
        $user1 = User::factory()->create();
        $user2 = User::factory()->create();

        // Logged in as user1
        $this->actingAs($user1, 'web');

        // Malicious: manipulate session to target user2
        session(['activeProfileType' => User::class, 'activeProfileId' => $user2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportContacts', 'json');



        $response->assertStatus(403);
    }

    /**
     * Test organization can export own messages
     *
     * @test
     */
    public function organization_can_export_own_messages()
    {
        $user = User::factory()->create();
        $organization = Organization::factory()->create();
        $organization->users()->attach($user->id);
        $recipient = User::factory()->create();

        // Create a conversation from organization
        $organization->sendMessageTo($recipient, 'Org message');

        $this->actingAs($user, 'web');
        $this->actingAs($organization, 'organization');
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $organization->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportMessages', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test organization cannot export another organization's messages
     *
     * @test
     */
    public function organization_cannot_export_another_organizations_messages()
    {
        $user = User::factory()->create();
        $org1 = Organization::factory()->create();
        $org2 = Organization::factory()->create();
        $org1->users()->attach($user->id);

        $this->actingAs($user, 'web');
        $this->actingAs($org1, 'organization');

        // Malicious: manipulate session to target org2
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $org2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportMessages', 'json');

        $response->assertStatus(403);
    }

    /**
     * Test organization can export own tags
     *
     * @test
     */
    public function organization_can_export_own_tags()
    {
        $user = User::factory()->create();
        $organization = Organization::factory()->create();
        $organization->users()->attach($user->id);

        // Create a tag and attach to organization
        $tag = Tag::factory()->create();
        $organization->tags()->attach($tag->id);

        $this->actingAs($user, 'web');
        $this->actingAs($organization, 'organization');
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $organization->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTags', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test organization cannot export another organization's tags
     *
     * @test
     */
    public function organization_cannot_export_another_organizations_tags()
    {
        $user = User::factory()->create();
        $org1 = Organization::factory()->create();
        $org2 = Organization::factory()->create();
        $org1->users()->attach($user->id);

        $this->actingAs($user, 'web');
        $this->actingAs($org1, 'organization');

        // Malicious: manipulate session to target org2
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $org2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTags', 'json');

        $response->assertStatus(403);
    }

    /**
     * Test organization can export own contacts
     *
     * @test
     */
    public function organization_can_export_own_contacts()
    {
        $user = User::factory()->create();
        $organization = Organization::factory()->create();
        $organization->users()->attach($user->id);

        $this->actingAs($user, 'web');
        $this->actingAs($organization, 'organization');
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $organization->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportContacts', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test organization cannot export another organization's contacts
     *
     * @test
     */
    public function organization_cannot_export_another_organizations_contacts()
    {
        $user = User::factory()->create();
        $org1 = Organization::factory()->create();
        $org2 = Organization::factory()->create();
        $org1->users()->attach($user->id);

        $this->actingAs($user, 'web');
        $this->actingAs($org1, 'organization');

        // Malicious: manipulate session to target org2
        session(['activeProfileType' => Organization::class, 'activeProfileId' => $org2->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportContacts', 'json');

        $response->assertStatus(403);
    }

    /**
     * Test cross-guard attack: web user cannot export bank data
     *
     * @test
     */
    public function web_user_cannot_export_bank_data_cross_guard_attack()
    {
        $user = User::factory()->create();
        $bank = Bank::factory()->create();
        $bank->managers()->attach($user->id);

        // Logged in as user (web guard)
        $this->actingAs($user, 'web');

        // Malicious: manipulate session to target bank profile
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportProfileData', 'json');



        $response->assertStatus(403);
    }

    /**
     * Test bank can export own data when properly authenticated
     *
     * @test
     */
    public function bank_can_export_own_data_when_properly_authenticated()
    {
        $user = User::factory()->create();
        $bank = Bank::factory()->create();
        $bank->managers()->attach($user->id);

        // Properly logged in as bank
        $this->actingAs($bank, 'bank');
        session(['activeProfileType' => Bank::class, 'activeProfileId' => $bank->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportProfileData', 'json');

        $response->assertStatus(200);
    }

    /**
     * Test unauthenticated user cannot export any data
     *
     * @test
     */
    public function unauthenticated_user_cannot_export_data()
    {
        $user = User::factory()->create();

        // Not authenticated
        session(['activeProfileType' => User::class, 'activeProfileId' => $user->id]);

        $response = Livewire::test(\App\Http\Livewire\Profile\ExportProfileData::class)
            ->call('exportTransactions', 'json');

        // Should return 401 (not authenticated) rather than 403 (authenticated but unauthorized)
        $response->assertStatus(401);
    }
}
