<?php

namespace Tests\Unit\Services;

use App\Models\Category;
use App\Models\Order;
use App\Models\Product;
use App\Services\AnalyticsService;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class AnalyticsServiceTest extends TestCase
{
    use RefreshDatabase;

    private AnalyticsService $analytics;

    private Category $category;

    protected function setUp(): void
    {
        parent::setUp();
        $this->analytics = app(AnalyticsService::class);
        $this->category = Category::factory()->create();
    }

    private function order(array $overrides = []): Order
    {
        return Order::create(array_merge([
            'order_number' => 'NYR-'.uniqid(), 'customer_name' => 'x', 'customer_phone' => 'x',
            'shipping_address' => 'x', 'shipping_city' => 'x', 'shipping_area' => 'x',
            'subtotal' => 1000, 'shipping_charge' => 0, 'grand_total' => 1000,
            'payment_method' => 'cod', 'payment_status' => 'pending', 'order_status' => 'confirmed',
        ], $overrides));
    }

    public function test_sales_trend_excludes_cancelled_orders_and_fills_gaps_with_zero(): void
    {
        $this->order(['grand_total' => 500, 'created_at' => now()]);
        $this->order(['grand_total' => 9999, 'order_status' => 'cancelled', 'created_at' => now()]);

        $result = $this->analytics->salesTrend(now()->subDays(2), now());

        $this->assertCount(3, $result['labels']);
        $this->assertSame(500.0, end($result['data']));
        $this->assertSame(0.0, $result['data'][0]);
    }

    public function test_order_status_breakdown_always_includes_all_six_statuses(): void
    {
        $this->order(['order_status' => 'pending']);
        $this->order(['order_status' => 'pending']);

        $result = $this->analytics->orderStatusBreakdown();

        $this->assertCount(6, $result['labels']);
        $this->assertSame(2, $result['data'][array_search('Pending', $result['labels'])]);
        $this->assertSame(0, $result['data'][array_search('Delivered', $result['labels'])]);
    }

    public function test_top_products_ranks_by_quantity_sold(): void
    {
        $productA = Product::factory()->for($this->category)->create(['name' => 'A']);
        $productB = Product::factory()->for($this->category)->create(['name' => 'B']);

        $order = $this->order();
        $order->items()->create(['product_id' => $productA->id, 'product_name' => 'A', 'sku' => 'A1', 'price' => 1000, 'quantity' => 3, 'subtotal' => 3000]);
        $order->items()->create(['product_id' => $productB->id, 'product_name' => 'B', 'sku' => 'B1', 'price' => 1000, 'quantity' => 10, 'subtotal' => 10000]);

        $result = $this->analytics->topProducts(limit: 5);

        $this->assertSame('B', $result->first()->product_name);
    }

    public function test_category_performance_sums_revenue_per_category(): void
    {
        $silk = Category::factory()->create(['name' => 'Silk']);
        $lawnProduct = Product::factory()->for($this->category)->create();
        $silkProduct = Product::factory()->for($silk)->create();

        $order = $this->order();
        $order->items()->create(['product_id' => $lawnProduct->id, 'product_name' => 'x', 'sku' => 'x', 'price' => 1000, 'quantity' => 1, 'subtotal' => 4000]);
        $order->items()->create(['product_id' => $silkProduct->id, 'product_name' => 'y', 'sku' => 'y', 'price' => 1000, 'quantity' => 1, 'subtotal' => 1000]);

        $result = $this->analytics->categoryPerformance(now()->subDay(), now());

        $this->assertSame($this->category->name, $result->first()->category);
        $this->assertEquals(4000, $result->first()->revenue);
    }

    public function test_summary_excludes_cancelled_and_computes_average(): void
    {
        $this->order(['grand_total' => 1000]);
        $this->order(['grand_total' => 3000]);
        $this->order(['grand_total' => 99999, 'order_status' => 'cancelled']);

        $result = $this->analytics->summary(now()->subDay(), now());

        $this->assertSame(2, $result['total_orders']);
        $this->assertSame(4000.0, $result['total_revenue']);
        $this->assertSame(2000.0, $result['average_order_value']);
    }
}
