<?php

namespace Tests\Unit;

use App\Models\AdditionalCharge;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Schema;
use Tests\TestCase;

class AdditionalChargeTest extends TestCase
{
    protected function setUp(): void
    {
        parent::setUp();

        Schema::dropIfExists('additional_charges');
        Schema::dropIfExists('invoices');
        Schema::dropIfExists('users');

        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('firstname')->nullable();
            $table->string('lastname')->nullable();
        });

        Schema::create('invoices', function (Blueprint $table) {
            $table->id();
            $table->string('invoice_number')->nullable();
        });

        Schema::create('additional_charges', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('parent_id')->nullable();
            $table->unsignedBigInteger('invoice_id')->nullable();
            $table->string('school_year', 20);
            $table->string('semester', 20);
            $table->string('charge_type', 20);
            $table->string('title');
            $table->text('description')->nullable();
            $table->decimal('amount', 10, 2);
            $table->date('due_date')->nullable();
            $table->string('status', 20);
            $table->unsignedBigInteger('created_by')->nullable();
            $table->timestamps();
        });
    }

    public function test_scope_by_parent_term_filters_status_and_orders_desc(): void
    {
        $parentId = 1;

        AdditionalCharge::create([
            'parent_id' => $parentId,
            'invoice_id' => null,
            'school_year' => '2024-2025',
            'semester' => 'Fall',
            'charge_type' => 'extra',
            'title' => 'Older',
            'description' => null,
            'amount' => 10.00,
            'due_date' => '2024-09-01',
            'status' => 'pending',
            'created_by' => null,
        ]);

        $latest = AdditionalCharge::create([
            'parent_id' => $parentId,
            'invoice_id' => null,
            'school_year' => '2024-2025',
            'semester' => 'Fall',
            'charge_type' => 'extra',
            'title' => 'Latest',
            'description' => null,
            'amount' => 20.00,
            'due_date' => '2024-10-01',
            'status' => 'pending',
            'created_by' => null,
        ]);

        AdditionalCharge::create([
            'parent_id' => $parentId,
            'invoice_id' => null,
            'school_year' => '2024-2025',
            'semester' => 'Fall',
            'charge_type' => 'extra',
            'title' => 'Applied',
            'description' => null,
            'amount' => 5.00,
            'due_date' => '2024-08-01',
            'status' => 'applied',
            'created_by' => null,
        ]);

        $results = AdditionalCharge::query()
            ->byParentTerm($parentId, '2024-2025', 'Fall', 'pending')
            ->get();

        $this->assertCount(2, $results);
        $this->assertSame($latest->id, $results->first()->id);
        $this->assertSame('pending', $results->first()->status);
    }

    public function test_mark_applied_updates_status_and_invoice(): void
    {
        $invoiceId = 1;

        $first = AdditionalCharge::create([
            'parent_id' => 1,
            'invoice_id' => null,
            'school_year' => '2024-2025',
            'semester' => 'Fall',
            'charge_type' => 'extra',
            'title' => 'Charge 1',
            'description' => null,
            'amount' => 15.00,
            'due_date' => null,
            'status' => 'pending',
            'created_by' => null,
        ]);

        $second = AdditionalCharge::create([
            'parent_id' => 1,
            'invoice_id' => null,
            'school_year' => '2024-2025',
            'semester' => 'Fall',
            'charge_type' => 'extra',
            'title' => 'Charge 2',
            'description' => null,
            'amount' => 25.00,
            'due_date' => null,
            'status' => 'pending',
            'created_by' => null,
        ]);

        $model = new AdditionalCharge();
        $result = $model->markApplied([$first->id, (string) $second->id], $invoiceId);

        $this->assertTrue($result);
        $this->assertSame('applied', $first->refresh()->status);
        $this->assertSame($invoiceId, $first->invoice_id);
        $this->assertSame('applied', $second->refresh()->status);
        $this->assertSame($invoiceId, $second->invoice_id);
    }

    public function test_list_all_for_term_falls_back_to_year(): void
    {
        $parentId = 1;
        $invoiceId = 1;

        DB::table('users')->insert([
            'id' => $parentId,
            'firstname' => 'Sara',
            'lastname' => 'Khan',
        ]);

        DB::table('invoices')->insert([
            'id' => $invoiceId,
            'invoice_number' => 'INV-1',
        ]);

        AdditionalCharge::create([
            'parent_id' => $parentId,
            'invoice_id' => $invoiceId,
            'school_year' => '2024-2025',
            'semester' => 'Fall',
            'charge_type' => 'extra',
            'title' => 'Fee',
            'description' => null,
            'amount' => 30.00,
            'due_date' => null,
            'status' => 'pending',
            'created_by' => null,
        ]);

        $paginator = (new AdditionalCharge())->listAllForTerm('2024-2025', 'Spring', null, null, 50, true);

        $this->assertSame(1, $paginator->total());
        $first = $paginator->items()[0];
        $this->assertSame('Khan, Sara', $first->parent_name);
        $this->assertSame('INV-1', $first->invoice_number);
    }

    public function test_list_all_for_term_filters_by_search_query(): void
    {
        $parentId = 1;
        $invoiceId = 1;

        DB::table('users')->insert([
            'id' => $parentId,
            'firstname' => 'Amina',
            'lastname' => 'Hassan',
        ]);

        DB::table('invoices')->insert([
            'id' => $invoiceId,
            'invoice_number' => 'INV-2025-001',
        ]);

        AdditionalCharge::create([
            'parent_id' => $parentId,
            'invoice_id' => $invoiceId,
            'school_year' => '2024-2025',
            'semester' => 'Fall',
            'charge_type' => 'extra',
            'title' => 'Math Club Fee',
            'description' => 'After school enrichment',
            'amount' => 30.00,
            'due_date' => null,
            'status' => 'pending',
            'created_by' => null,
        ]);

        AdditionalCharge::create([
            'parent_id' => $parentId,
            'invoice_id' => $invoiceId,
            'school_year' => '2024-2025',
            'semester' => 'Fall',
            'charge_type' => 'extra',
            'title' => 'Science Lab',
            'description' => 'Lab supplies',
            'amount' => 20.00,
            'due_date' => null,
            'status' => 'pending',
            'created_by' => null,
        ]);

        $paginator = (new AdditionalCharge())->listAllForTerm('2024-2025', 'Fall', null, 'Math', 50, true);

        $this->assertSame(1, $paginator->total());
        $this->assertSame('Math Club Fee', $paginator->items()[0]->title);

        $byDescription = (new AdditionalCharge())->listAllForTerm('2024-2025', 'Fall', null, 'enrichment', 50, true);
        $this->assertSame(1, $byDescription->total());
        $this->assertSame('Math Club Fee', $byDescription->items()[0]->title);

        $byParentName = (new AdditionalCharge())->listAllForTerm('2024-2025', 'Fall', null, 'Hassan', 50, true);
        $this->assertSame(2, $byParentName->total());

        $byInvoice = (new AdditionalCharge())->listAllForTerm('2024-2025', 'Fall', null, 'INV-2025-001', 50, true);
        $this->assertSame(2, $byInvoice->total());
    }
}
