<?php

namespace Tests\Feature;

use App\Models\Order;
use App\Models\Product;
use App\Models\ProductVariant;
use App\Models\Setting;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Http\UploadedFile;
use Illuminate\Support\Facades\Storage;
use Tests\TestCase;

class CheckoutTest extends TestCase
{
    use RefreshDatabase;

    private Product $product;

    private ProductVariant $variant;

    protected function setUp(): void
    {
        parent::setUp();
        Setting::set('payments.cod.restricted_city', 'Karachi');
        Setting::set('shipping.flat_rate', 250);
        Setting::set('shipping.free_shipping_threshold', 0);

        $this->product = Product::factory()->create(['original_price' => 2000, 'sale_price' => null]);
        $this->variant = ProductVariant::factory()->for($this->product)->withStock(10)->create();
    }

    private function checkoutPayload(array $overrides = []): array
    {
        return array_merge([
            'customer_name' => 'Ayesha Khan', 'customer_phone' => '03001234567', 'customer_email' => 'ayesha@example.com',
            'shipping_address' => '123 Clifton Block 4', 'shipping_city' => 'Karachi', 'shipping_area' => 'Clifton',
            'payment_method' => 'cod',
        ], $overrides);
    }

    public function test_checkout_page_redirects_to_cart_when_empty(): void
    {
        $this->get('/checkout')->assertRedirect(route('cart.index'));
    }

    public function test_cod_order_can_be_placed_for_the_allowed_city(): void
    {
        $user = $this->customer();
        $this->actingAs($user)->post(route('cart.add', $this->product), ['variant_id' => $this->variant->id, 'quantity' => 2]);

        $response = $this->actingAs($user)->post('/checkout', $this->checkoutPayload());

        $order = Order::first();
        $response->assertRedirect(route('orders.show', $order));
        $this->assertSame(4000.0, (float) $order->subtotal);
        $this->assertSame(4250.0, (float) $order->grand_total);
        $this->assertSame(2, $order->items->first()->quantity);
    }

    public function test_cod_order_is_rejected_outside_the_allowed_city(): void
    {
        $user = $this->customer();
        $this->actingAs($user)->post(route('cart.add', $this->product), ['variant_id' => $this->variant->id, 'quantity' => 1]);

        $response = $this->actingAs($user)->post('/checkout', $this->checkoutPayload(['shipping_city' => 'Lahore']));

        $response->assertSessionHasErrors('payment_method');
        $this->assertDatabaseCount('orders', 0);
    }

    public function test_easypaisa_order_stores_reference_and_proof_image(): void
    {
        Storage::fake('public');
        $user = $this->customer();
        $this->actingAs($user)->post(route('cart.add', $this->product), ['variant_id' => $this->variant->id, 'quantity' => 1]);

        $this->actingAs($user)->post('/checkout', $this->checkoutPayload([
            'shipping_city' => 'Lahore', 'payment_method' => 'easypaisa',
            'payment_reference' => 'TXN123456', 'payment_proof' => UploadedFile::fake()->image('proof.jpg'),
        ]));

        $payment = Order::first()->payments->first();
        $this->assertSame('TXN123456', $payment->reference_number);
        Storage::disk('public')->assertExists($payment->proof_image);
    }

    public function test_placing_an_order_deducts_stock_and_clears_the_cart(): void
    {
        $user = $this->customer();
        $this->actingAs($user)->post(route('cart.add', $this->product), ['variant_id' => $this->variant->id, 'quantity' => 3]);

        $this->actingAs($user)->post('/checkout', $this->checkoutPayload());

        $this->assertSame(7, $this->variant->inventory->fresh()->quantity);
        $this->assertDatabaseCount('cart_items', 0);
    }

    public function test_cannot_order_more_than_currently_available_stock(): void
    {
        $user = $this->customer();
        $this->actingAs($user)->post(route('cart.add', $this->product), ['variant_id' => $this->variant->id, 'quantity' => 5]);
        $this->variant->inventory->update(['quantity' => 2]); // dropped after adding to cart

        $response = $this->actingAs($user)->post('/checkout', $this->checkoutPayload());

        $response->assertRedirect(route('cart.index'));
        $response->assertSessionHas('error');
        $this->assertDatabaseCount('orders', 0);
    }

    public function test_buy_now_adds_item_and_redirects_straight_to_checkout(): void
    {
        $response = $this->post(route('checkout.buyNow', $this->product), ['variant_id' => $this->variant->id, 'quantity' => 1]);

        $response->assertRedirect(route('checkout.index'));
        $this->assertDatabaseHas('cart_items', ['product_variant_id' => $this->variant->id, 'quantity' => 1]);
    }
}
