<?php

namespace Tests\Feature\Audit;

use App\Mail\ShopOrderConfirmationMail;
use App\Models\Central\Company;
use App\Models\Central\Plan;
use App\Models\Tenant\OnlineOrder;
use App\Models\Tenant\Part;
use App\Models\Tenant\ShopCustomer;
use App\Models\Tenant\Warehouse;
use App\Models\Tenant\WarehouseEvent;
use App\Services\Warehouse\WarehouseService;
use App\Tenancy\TenantManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Tests\TestCase;

/**
 * End-to-end shop journey: customer registers → adds to cart → checks out →
 * receives confirmation email → admin fulfills → WarehouseService.issue runs →
 * stock decreases → tracking page reachable.
 *
 * Exercises ShopAuthController, ShopController, OnlineOrder, OnlineOrderItem,
 * ShopCustomer, ShopOrderNotifier, WarehouseService, and the tracking route.
 */
class ShopJourneyE2ETest extends TestCase
{
    use RefreshDatabase;

    public function test_full_shop_journey_registered_customer(): void
    {
        $ctx = $this->bootShop('e2e-shop');
        $svc = app(WarehouseService::class);

        // Stock a published part: 20 in inventory.
        $part = Part::create([
            'name' => 'Plăcuțe BMW', 'article' => 'BMW-001', 'brand' => 'TRW',
            'sell_price' => 250, 'buy_price' => 150,
            'qty' => 0, 'unit' => 'buc',
            'is_active' => true, 'is_published' => true,
        ]);
        $svc->receive($part, 20, 150);
        $this->assertEquals(20.0, (float) $part->fresh()->qty);

        Mail::fake();

        $base = 'http://e2e-shop.service.mir.md';

        // 1. Register.
        $this->post("$base/shop/register", [
            'name' => 'Tester', 'phone' => '+37377012345',
            'email' => 'tester@example.com',
            'password' => 'secret123', 'password_confirmation' => 'secret123',
        ])->assertRedirect('/shop/account');

        $customer = ShopCustomer::where('phone', '+37377012345')->first();
        $this->assertNotNull($customer);
        $this->assertTrue(Auth::guard('shop')->check());

        // 2. Browse catalog (anonymous-safe, but we're logged in).
        $r = $this->get("$base/shop");
        $r->assertOk();
        $r->assertSee('Plăcuțe BMW');

        // 3. Add to cart.
        $this->post("$base/shop/part/{$part->id}/add", ['qty' => 2])
            ->assertRedirect('/shop/cart');

        $this->get("$base/shop/cart")->assertOk()->assertSee('500.00');

        // 4. Checkout.
        $this->get("$base/shop/checkout")
            ->assertOk()
            ->assertSee('Tester', false)        // prefilled from logged-in customer
            ->assertSee('+37377012345');

        $this->post("$base/shop/checkout", [
            'customer_name' => 'Tester',
            'customer_phone' => '+37377012345',
            'customer_email' => 'tester@example.com',
            'delivery_method' => 'pickup',
        ])->assertRedirect();

        $order = OnlineOrder::first();
        $this->assertNotNull($order);
        $this->assertEquals($customer->id, $order->shop_customer_id);
        $this->assertEquals(500.0, (float) $order->total);

        // 5. Confirmation email sent to customer.
        Mail::assertSent(ShopOrderConfirmationMail::class, fn ($m) => $m->order->id === $order->id);

        // 6. Tracking page reachable by token (NO auth).
        Auth::guard('shop')->logout();
        $r = $this->get($order->trackingUrl());
        $r->assertOk();
        $r->assertSee('#' . $order->number);
        $r->assertSee('Plăcuțe BMW');

        // 7. Admin (back in tenant context) fulfills via service::issue.
        $svc->issue($part, 2, null, $order, 'shop fulfill');
        $part->refresh();
        $this->assertEquals(18.0, (float) $part->qty, 'stock decreased by 2');

        // 8. The warehouse event records the issue with ref pointing at the order.
        $event = WarehouseEvent::where('part_id', $part->id)
            ->where('type', 'issue')
            ->latest('id')->first();
        $this->assertNotNull($event);
        $this->assertEquals(-2.0, (float) $event->qty_delta);
        $this->assertStringContainsString('OnlineOrder', (string) $event->ref_type);
    }

    public function test_guest_checkout_still_works_without_account(): void
    {
        $this->bootShop('guest');
        $part = Part::create([
            'name' => 'Filtru', 'sell_price' => 50, 'qty' => 5, 'unit' => 'buc',
            'is_active' => true, 'is_published' => true,
        ]);

        $base = 'http://guest.service.mir.md/shop';

        $this->post("$base/part/{$part->id}/add", ['qty' => 1])->assertRedirect();
        $this->post("$base/checkout", [
            'customer_name' => 'Guest', 'customer_phone' => '+37399999999',
            'delivery_method' => 'pickup',
        ])->assertRedirect();

        $order = OnlineOrder::first();
        $this->assertNotNull($order);
        $this->assertNull($order->shop_customer_id);
        $this->assertEquals(50.0, (float) $order->total);
    }

    private function bootShop(string $slug): array
    {
        $plan = Plan::firstOrCreate(['slug' => 'test'], ['name' => 'T', 'price' => 0, 'features' => []]);
        $company = Company::create([
            'plan_id' => $plan->id, 'slug' => $slug,
            'name' => ucfirst($slug), 'status' => 'active',
            'settings' => ['shop' => ['enabled' => true, 'delivery_methods' => ['pickup']]],
        ]);
        app(TenantManager::class)->setCurrent($company);

        $wh = Warehouse::create([
            'code' => 'MAIN', 'name' => 'Main',
            'is_default' => true, 'is_active' => true,
        ]);
        $company->forceFill(['default_warehouse_id' => $wh->id])->saveQuietly();
        return compact('company');
    }
}
