<?php

namespace Tests\Feature;

use App\Models\Product;
use App\Models\ReconImportBatch;
use App\Models\ReconImportRow;
use App\Models\ReconProductMapping;
use App\Models\ReconProductMappingComponent;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Spatie\Permission\Models\Role;
use Tests\TestCase;

class ReconImportBatchTest extends TestCase
{
    use RefreshDatabase;

    private function manager(): User
    {
        Role::firstOrCreate(['name' => 'manager', 'guard_name' => 'web']);
        $user = User::factory()->create();
        $user->assignRole('manager');

        return $user;
    }

    private function rows(): array
    {
        return [
            ['row_number' => 2, 'sale_date' => '2026-07-01', 'external_label' => 'Es Krim Coklat 1L', 'qty' => 3, 'amount' => 90000],
            ['row_number' => 3, 'sale_date' => '2026-07-02', 'external_label' => 'Es Krim Vanila 1L', 'qty' => 2, 'amount' => 60000],
            ['row_number' => 4, 'sale_date' => '2026-07-03', 'external_label' => 'Es Krim Coklat 1L', 'qty' => 1, 'amount' => 30000, 'order_status' => 'Dibatalkan', 'excluded' => true],
        ];
    }

    public function test_import_creates_batch_and_rows_with_date_range_from_active_rows(): void
    {
        $response = $this->actingAs($this->manager(), 'sanctum')->postJson('/api/recon/batches', [
            'channel'   => 'shopee',
            'file_name' => 'shopee-juli.xlsx',
            'rows'      => $this->rows(),
        ]);

        $response->assertStatus(201)
            ->assertJsonPath('date_from', '2026-07-01')
            ->assertJsonPath('date_to', '2026-07-02')
            ->assertJsonPath('row_count', 3)
            ->assertJsonPath('excluded_count', 1);

        $batch = ReconImportBatch::first();
        $this->assertSame('shopee', $batch->channel);
        $this->assertSame(3, $batch->rows()->count());
        $this->assertSame(1, $batch->rows()->where('excluded', true)->count());
    }

    public function test_existing_mapping_auto_resolves_product_and_unmapped_keys_are_returned(): void
    {
        $product = Product::create(['sku' => 'ESK-COK', 'name' => 'Es Krim Coklat', 'sell_price' => 30000]);
        $mapping = ReconProductMapping::create([
            'channel'      => 'shopee',
            'external_key' => 'es krim coklat 1l',
        ]);
        ReconProductMappingComponent::create([
            'mapping_id'     => $mapping->id,
            'product_id'     => $product->id,
            'qty_multiplier' => 1,
        ]);

        $response = $this->actingAs($this->manager(), 'sanctum')->postJson('/api/recon/batches', [
            'channel' => 'shopee',
            'rows'    => $this->rows(),
        ]);

        $response->assertStatus(201);
        $unmapped = collect($response->json('unmapped'));
        $this->assertCount(1, $unmapped);
        $this->assertSame('es krim vanila 1l', $unmapped[0]['external_key']);

        $this->assertSame(
            $product->id,
            ReconImportRow::where('external_key', 'es krim coklat 1l')->where('excluded', false)->first()->items->first()->product_id
        );
    }

    public function test_overlapping_period_returns_409_without_supersede(): void
    {
        $manager = $this->manager();
        $this->actingAs($manager, 'sanctum')->postJson('/api/recon/batches', [
            'channel' => 'shopee',
            'rows'    => $this->rows(),
        ])->assertStatus(201);

        $response = $this->actingAs($manager, 'sanctum')->postJson('/api/recon/batches', [
            'channel' => 'shopee',
            'rows'    => $this->rows(),
        ]);

        $response->assertStatus(409);
        $this->assertNotEmpty($response->json('overlapping'));
        $this->assertSame(1, ReconImportBatch::count());
    }

    public function test_supersede_marks_old_batch_and_keeps_new_one_active(): void
    {
        $manager = $this->manager();
        $first = $this->actingAs($manager, 'sanctum')->postJson('/api/recon/batches', [
            'channel' => 'shopee',
            'rows'    => $this->rows(),
        ])->json('batch_id');

        $second = $this->actingAs($manager, 'sanctum')->postJson('/api/recon/batches', [
            'channel'   => 'shopee',
            'supersede' => true,
            'rows'      => $this->rows(),
        ]);

        $second->assertStatus(201);

        $old = ReconImportBatch::find($first);
        $this->assertSame('superseded', $old->status);
        $this->assertSame($second->json('batch_id'), $old->superseded_by);
        $this->assertSame('active', ReconImportBatch::find($second->json('batch_id'))->status);
    }

    public function test_different_channel_does_not_conflict(): void
    {
        $manager = $this->manager();
        $this->actingAs($manager, 'sanctum')->postJson('/api/recon/batches', [
            'channel' => 'shopee',
            'rows'    => $this->rows(),
        ])->assertStatus(201);

        $this->actingAs($manager, 'sanctum')->postJson('/api/recon/batches', [
            'channel' => 'tokopedia',
            'rows'    => $this->rows(),
        ])->assertStatus(201);
    }

    public function test_operator_role_is_forbidden(): void
    {
        Role::firstOrCreate(['name' => 'operator', 'guard_name' => 'web']);
        $operator = User::factory()->create();
        $operator->assignRole('operator');

        $this->actingAs($operator, 'sanctum')->postJson('/api/recon/batches', [
            'channel' => 'shopee',
            'rows'    => $this->rows(),
        ])->assertStatus(403);
    }
}
