<?php

namespace Tests\Feature;

use App\Models\DonorFinancialPortfolio;
use App\Models\Order;
use App\Models\OrderFinance;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class OrderRejectionAllocationTest extends TestCase
{
    use RefreshDatabase;

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

    public function test_rejected_orders_do_not_count_toward_portfolio_allocation()
    {
        // Create a user
        $user = User::factory()->create();
        $this->actingAs($user);

        // Create a donor portfolio with 1000 balance
        $portfolio = DonorFinancialPortfolio::create([
            'name' => 'Test Portfolio',
            'balance' => 1000.00,
        ]);

        // Create two orders
        $activeOrder = Order::factory()->create([
            'status' => Order::STATUS_CLASSIFICATION,
            'created_by' => $user->id,
        ]);

        $rejectedOrder = Order::factory()->create([
            'status' => Order::STATUS_CLASSIFICATION,
            'created_by' => $user->id,
        ]);

        // Allocate 300 to active order and 200 to order that will be rejected
        $portfolio->orders()->attach($activeOrder->id, ['allocated_amount' => 300.00]);
        $portfolio->orders()->attach($rejectedOrder->id, ['allocated_amount' => 200.00]);

        // Initially, total allocated should be 500 (300 + 200)
        $this->assertEquals(500.00, $portfolio->fresh()->total_allocated);
        $this->assertEquals(500.00, $portfolio->fresh()->remaining_balance);

        // Reject the second order
        $rejectedOrder->reject('Order rejected for testing');

        // After rejection, total allocated should only be 300 (from active order)
        $portfolio = $portfolio->fresh();
        $this->assertEquals(300.00, $portfolio->total_allocated);
        $this->assertEquals(700.00, $portfolio->remaining_balance);

        // Verify the rejected order shows 0 allocated funding
        $this->assertEquals(0.0, $rejectedOrder->fresh()->getTotalAllocatedFunding());

        // Verify the active order still shows its allocated funding
        $this->assertEquals(300.00, $activeOrder->fresh()->getTotalAllocatedFunding());
    }

    public function test_rejecting_order_removes_portfolio_allocations()
    {
        // Create a user
        $user = User::factory()->create();
        $this->actingAs($user);

        // Create portfolios
        $portfolio1 = DonorFinancialPortfolio::create([
            'name' => 'Portfolio 1',
            'balance' => 500.00,
        ]);

        $portfolio2 = DonorFinancialPortfolio::create([
            'name' => 'Portfolio 2',
            'balance' => 500.00,
        ]);

        // Create an order with finance
        $order = Order::factory()->create([
            'status' => Order::STATUS_CLASSIFICATION,
            'created_by' => $user->id,
        ]);

        OrderFinance::factory()->create([
            'order_id' => $order->id,
            'offer_price' => 400.00,
            'additional_fees' => 100.00,
        ]);

        // Allocate from both portfolios
        $portfolio1->orders()->attach($order->id, ['allocated_amount' => 200.00]);
        $portfolio2->orders()->attach($order->id, ['allocated_amount' => 300.00]);

        // Verify allocations exist
        $this->assertCount(2, $order->donorFinancialPortfolios);
        $this->assertEquals(500.00, $order->getTotalAllocatedFunding());

        // Reject the order
        $order->reject('Order rejected for testing');

        // Verify allocations are removed
        $order = $order->fresh();
        $this->assertCount(0, $order->donorFinancialPortfolios);
        $this->assertEquals(0.0, $order->getTotalAllocatedFunding());

        // Verify portfolios show correct remaining balance
        $this->assertEquals(500.00, $portfolio1->fresh()->remaining_balance);
        $this->assertEquals(500.00, $portfolio2->fresh()->remaining_balance);
    }

    public function test_order_rejection_creates_audit_trail()
    {
        // Create a user
        $user = User::factory()->create();
        $this->actingAs($user);

        // Create a portfolio and order
        $portfolio = DonorFinancialPortfolio::create([
            'name' => 'Test Portfolio',
            'balance' => 1000.00,
        ]);

        $order = Order::factory()->create([
            'status' => Order::STATUS_CLASSIFICATION,
            'created_by' => $user->id,
        ]);

        // Allocate funds
        $portfolio->orders()->attach($order->id, ['allocated_amount' => 250.00]);

        // Reject the order
        $order->reject('Order rejected due to compliance issues');

        // Check that activity log entries were created
        $this->assertDatabaseHas('activity_log', [
            'subject_id' => $order->id,
            'subject_type' => Order::class,
            'event' => 'rejected',
            'causer_id' => $user->id,
        ]);

        $this->assertDatabaseHas('activity_log', [
            'subject_id' => $order->id,
            'subject_type' => Order::class,
            'event' => 'portfolio_deallocated',
            'causer_id' => $user->id,
        ]);
    }

    public function test_multiple_portfolio_deallocation_on_rejection()
    {
        // Create a user
        $user = User::factory()->create();
        $this->actingAs($user);

        // Create multiple portfolios
        $portfolios = DonorFinancialPortfolio::factory()->count(3)->create([
            'balance' => 1000.00,
        ]);

        // Create an order
        $order = Order::factory()->create([
            'status' => Order::STATUS_CLASSIFICATION,
            'created_by' => $user->id,
        ]);

        // Allocate from all portfolios
        $allocations = [150.00, 200.00, 100.00];
        foreach ($portfolios as $index => $portfolio) {
            $portfolio->orders()->attach($order->id, ['allocated_amount' => $allocations[$index]]);
        }

        // Verify initial state
        $this->assertEquals(450.00, $order->getTotalAllocatedFunding());

        // Check each portfolio's allocated amount
        foreach ($portfolios as $index => $portfolio) {
            $this->assertEquals($allocations[$index], $portfolio->fresh()->total_allocated);
        }

        // Reject the order
        $order->reject('Multiple portfolio test rejection');

        // Verify all allocations are removed
        $this->assertEquals(0.0, $order->fresh()->getTotalAllocatedFunding());

        // Verify all portfolios are back to full balance
        foreach ($portfolios as $portfolio) {
            $portfolio = $portfolio->fresh();
            $this->assertEquals(0.0, $portfolio->total_allocated);
            $this->assertEquals(1000.00, $portfolio->remaining_balance);
        }
    }
}
