<?php

namespace Tests\Feature;

use App\Enums\LineStatus;
use App\Models\CashDrawer;
use App\Models\Customer;
use App\Models\Invoice;
use App\Models\Line;
use App\Models\TelecomCompany;
use App\Services\CashDrawerService;
use App\Services\InvoiceService;
use App\Services\LineSaleService;
use App\Services\LineService;
use Tests\TestCase;

class OperationsTest extends TestCase
{
    public function test_cash_transaction_and_daily_closing(): void
    {
        $admin = $this->admin();
        $cash = app(CashDrawerService::class);
        $drawer = $cash->open($admin, '100.00');
        $this->assertEquals('open', $drawer->status);

        $company = TelecomCompany::factory()->create();
        $line = Line::factory()->create(['telecom_company_id' => $company->id]);
        $customer = Customer::factory()->create();
        app(LineSaleService::class)->sell([
            'customer_id' => $customer->id,
            'line_id' => $line->id,
            'line_price' => '50.00',
            'paid' => '50.00',
            'payment_method' => 'cash',
            'sale_date' => now()->toDateString(),
        ], $admin);

        $summary = $cash->summary($drawer->fresh());
        $this->assertTrue(bccomp($summary['expected_balance'], '150.00', 2) === 0);

        $closing = $cash->close($admin, '150.00');
        $this->assertEquals('closed', $drawer->fresh()->status);
        $this->assertEquals('0.00', $closing->difference);
        $this->assertEquals('150.00', $drawer->fresh()->expected_balance);
    }

    public function test_invoice_cancellation_keeps_record(): void
    {
        $admin = $this->admin();
        $company = TelecomCompany::factory()->create();
        $line = Line::factory()->create(['telecom_company_id' => $company->id, 'sale_price' => '20.00']);
        $customer = Customer::factory()->create();
        $sale = app(LineSaleService::class)->sell([
            'customer_id' => $customer->id,
            'line_id' => $line->id,
            'line_price' => '20.00',
            'paid' => '20.00',
            'payment_method' => 'cash',
            'sale_date' => now()->toDateString(),
        ], $admin);

        app(InvoiceService::class)->cancel($sale->invoice, $admin, 'correction');
        $this->assertDatabaseHas('invoices', ['id' => $sale->invoice_id, 'status' => 'cancelled']);
        $this->assertNotNull(Invoice::withTrashed()->find($sale->invoice_id));
    }

    public function test_ownership_transfer_is_recorded(): void
    {
        $admin = $this->admin();
        $company = TelecomCompany::factory()->create();
        $line = Line::factory()->create(['telecom_company_id' => $company->id, 'sale_price' => '10.00']);
        $from = Customer::factory()->create();
        $to = Customer::factory()->create();
        app(LineSaleService::class)->sell([
            'customer_id' => $from->id,
            'line_id' => $line->id,
            'line_price' => '10.00',
            'paid' => '10.00',
            'payment_method' => 'cash',
            'sale_date' => now()->toDateString(),
        ], $admin);

        app(LineService::class)->transfer($line->fresh(), [
            'customer_id' => $to->id,
            'reason' => 'customer request',
        ], $admin);

        $this->assertEquals($to->id, $line->fresh()->customer_id);
        $this->assertDatabaseHas('line_ownership_history', [
            'line_id' => $line->id,
            'previous_customer_id' => $from->id,
            'new_customer_id' => $to->id,
        ]);

        app(LineService::class)->returnLine($line->fresh(), $admin, 'returned by customer', LineStatus::Available);
        $this->assertNull($line->fresh()->customer_id);
        $this->assertEquals(LineStatus::Available, $line->fresh()->status);
        $this->assertGreaterThanOrEqual(3, $line->ownershipHistory()->count());
    }

    public function test_viewer_cannot_create_customers(): void
    {
        $viewer = $this->userWithRole('Viewer');
        $this->actingAs($viewer)->post(route('customers.store'), [
            'name' => 'X',
            'phone' => '011',
            'customer_type' => 'individual',
            'status' => 'active',
        ])->assertForbidden();
    }

    public function test_update_migrations_do_not_wipe_data(): void
    {
        $customer = Customer::factory()->create(['name' => 'Keep Me']);
        $this->artisan('migrate', ['--force' => true])->assertExitCode(0);
        $this->assertDatabaseHas('customers', ['id' => $customer->id, 'name' => 'Keep Me']);
    }
}
