<?php

namespace Tests\Feature;

use App\Models\Central\Company;
use App\Models\Central\Plan;
use App\Models\Tenant\Part;
use App\Models\Tenant\Purchase;
use App\Models\Tenant\PurchaseItem;
use App\Models\Tenant\Supplier;
use App\Models\Tenant\SupplierInvoiceMapping;
use App\Services\ExcelInvoiceImportService;
use App\Tenancy\TenantManager;
use Illuminate\Foundation\Testing\RefreshDatabase;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;
use Tests\TestCase;

class ExcelInvoiceImportTest extends TestCase
{
    use RefreshDatabase;

    private Company $company;
    private Supplier $supplier;

    protected function setUp(): void
    {
        parent::setUp();
        $plan = Plan::firstOrCreate(['slug' => 'test'], ['name' => 'T', 'price' => 0, 'features' => []]);
        $this->company = Company::create(['plan_id' => $plan->id, 'slug' => 'exc-' . uniqid(), 'name' => 'Exc Co', 'status' => 'active']);
        app(TenantManager::class)->setCurrent($this->company);
        $this->supplier = Supplier::create(['name' => 'Rossko MD', 'phone' => '+37322000000']);
    }

    private function makeXlsx(array $rows, string $headerName = 'Articol'): string
    {
        $spreadsheet = new Spreadsheet;
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setCellValue('A1', '');
        $sheet->setCellValue('B1', $headerName);
        $sheet->setCellValue('C1', 'Denumire');
        $sheet->setCellValue('D1', 'Brand');
        $sheet->setCellValue('E1', 'Cant');
        $sheet->setCellValue('F1', 'Preț');
        $r = 2;
        foreach ($rows as $row) {
            $sheet->setCellValue("B$r", $row[0]);
            $sheet->setCellValue("C$r", $row[1]);
            $sheet->setCellValue("D$r", $row[2]);
            $sheet->setCellValue("E$r", $row[3]);
            $sheet->setCellValue("F$r", $row[4]);
            $r++;
        }
        $tmp = tempnam(sys_get_temp_dir(), 'inv') . '.xlsx';
        (new Xlsx($spreadsheet))->save($tmp);
        return $tmp;
    }

    public function test_headers_preview_returns_first_5_rows_and_column_letters(): void
    {
        $path = $this->makeXlsx([
            ['W71221', 'Filtru ulei Mann', 'Mann', 10, 61.00],
            ['GDB1550', 'Plăcuțe TRW', 'TRW', 4, 280.00],
        ]);

        $svc = app(ExcelInvoiceImportService::class);
        $preview = $svc->headersPreview($path);

        $this->assertContains('B', $preview['columns']);
        $this->assertContains('F', $preview['columns']);
        $this->assertEquals('Articol', $preview['rows'][0]['B']);
        $this->assertEquals('Filtru ulei Mann', $preview['rows'][1]['C']);
        unlink($path);
    }

    public function test_preview_classifies_rows_as_found_or_new(): void
    {
        // Existing part in DB
        Part::create(['name' => 'Filtru ulei Mann W712/83', 'article' => 'W71221', 'buy_price' => 60, 'sell_price' => 85]);

        $path = $this->makeXlsx([
            ['W71221', 'Filtru ulei', 'Mann', 10, 61.00],
            ['NEW-001', 'Articol nou', 'Generic', 5, 30.00],
            ['', 'Fără cod', '', 1, 100.00],
        ]);

        $result = app(ExcelInvoiceImportService::class)->preview($path, [
            'article_col' => 'B', 'name_col' => 'C', 'brand_col' => 'D',
            'qty_col' => 'E', 'price_col' => 'F', 'header_row' => 1,
        ]);

        $this->assertEquals(3, $result['summary']['total']);
        $this->assertEquals(1, $result['summary']['found']);
        $this->assertEquals(1, $result['summary']['new']);
        $this->assertEquals(1, $result['summary']['no_article']);

        $this->assertEquals('found', $result['rows'][0]['status']);
        $this->assertEquals('new', $result['rows'][1]['status']);
        $this->assertEquals('no_article', $result['rows'][2]['status']);
        unlink($path);
    }

    public function test_import_creates_purchase_with_items_and_auto_creates_new_parts(): void
    {
        Part::create(['name' => 'Existing', 'article' => 'EX-1', 'buy_price' => 50]);
        $svc = app(ExcelInvoiceImportService::class);

        $path = $this->makeXlsx([
            ['EX-1', 'Existing', 'B1', 2, 50],
            ['NEW-A', 'New thing', 'B2', 3, 120],
        ]);

        $preview = $svc->preview($path, [
            'article_col' => 'B', 'name_col' => 'C', 'brand_col' => 'D',
            'qty_col' => 'E', 'price_col' => 'F', 'header_row' => 1,
        ]);
        $purchase = $svc->import($this->supplier, $preview['rows'], createNew: true);

        $this->assertNotNull($purchase);
        $this->assertEquals(2, PurchaseItem::where('purchase_id', $purchase->id)->count());
        // 2*50 + 3*120 = 460
        $this->assertEqualsWithDelta(460.0, (float) $purchase->total, 0.01);

        // NEW-A should have been auto-created as a Part
        $this->assertNotNull(Part::where('article', 'NEW-A')->first());
        unlink($path);
    }

    public function test_remember_mapping_persists_and_round_trips(): void
    {
        $mapping = ['article_col' => 'B', 'name_col' => 'C', 'qty_col' => 'E', 'price_col' => 'F', 'header_row' => 2];
        $svc = app(ExcelInvoiceImportService::class);

        $svc->rememberMapping($this->supplier, $mapping, 'rossko-march.xlsx');

        $loaded = $svc->rememberedMappingFor($this->supplier);
        $this->assertEquals('B', $loaded['article_col']);
        $this->assertEquals(2, $loaded['header_row']);

        // Update — should upsert, not duplicate
        $mapping['header_row'] = 3;
        $svc->rememberMapping($this->supplier, $mapping);
        $this->assertEquals(1, SupplierInvoiceMapping::where('supplier_id', $this->supplier->id)->count());
        $this->assertEquals(3, $svc->rememberedMappingFor($this->supplier)['header_row']);
    }

    public function test_decimal_parser_tolerates_european_format(): void
    {
        $path = $this->makeXlsx([
            ['EU-1', 'European', 'Brand', '2', '1 234,56'],
        ]);
        $preview = app(ExcelInvoiceImportService::class)->preview($path, [
            'article_col' => 'B', 'name_col' => 'C', 'qty_col' => 'E', 'price_col' => 'F', 'header_row' => 1,
        ]);
        $this->assertEqualsWithDelta(1234.56, $preview['rows'][0]['price'], 0.01);
        unlink($path);
    }
}
