<?php

namespace Database\Seeders\Demo;

use App\Models\Lookups\ReturnReason;
use App\Models\Lookups\Status;
use App\Models\Sales\Invoice;
use App\Services\ReturnService;
use Database\Seeders\Demo\Concerns\GeneratesDemoData;
use Illuminate\Database\Seeder;
use RuntimeException;

class ReturnSeeder extends Seeder
{
    use GeneratesDemoData;

    private const RETURN_COUNT = 40;

    private const GOOD_REASONS = [ReturnReason::WRONG_ITEM, ReturnReason::OVERSTOCK, ReturnReason::QUALITY, ReturnReason::MISTAKENLY_ORDERED, ReturnReason::OTHER];

    private const DAMAGE_REASONS = [ReturnReason::DAMAGE_TRANSIT, ReturnReason::DAMAGE_WAREHOUSE, ReturnReason::DAMAGE_CUSTOMER];

    public function run(): void
    {
        $returns = app(ReturnService::class);
        $paidId = Status::idOf(Status::CTX_INVOICE_PAYMENT, Status::PAID);
        $partialId = Status::idOf(Status::CTX_INVOICE_PAYMENT, Status::PARTIAL);

        $candidates = Invoice::whereIn('payment_status_id', array_filter([$paidId, $partialId]))
            ->whereNotNull('customer_id')
            ->whereNotNull('branch_id')
            ->with('items')
            ->inRandomOrder()
            ->limit(self::RETURN_COUNT * 2)
            ->get()
            ->filter(fn (Invoice $i) => $i->items->where('product_id', '!=', null)->isNotEmpty());

        $created = 0;
        foreach ($candidates as $invoice) {
            if ($created >= self::RETURN_COUNT) {
                break;
            }

            $eligibleItems = $invoice->items->whereNotNull('product_id')->values();
            $item = $eligibleItems->random();
            $isDamaged = fake()->boolean(35);

            $qty = (float) random_int(1, max(1, (int) $item->quantity));

            $line = [
                'invoice_id' => $invoice->id,
                'invoice_item_id' => $item->id,
                'product_id' => $item->product_id,
                'return_reason_code' => fake()->randomElement($isDamaged ? self::DAMAGE_REASONS : self::GOOD_REASONS),
                'quantity' => $qty,
                'unit_price' => (float) $item->unit_price,
            ];

            if (! $isDamaged) {
                $line['is_add_back_to_stock'] = true;
            }

            try {
                $return = $returns->create(
                    header: [
                        'customer_id' => $invoice->customer_id,
                        'branch_id' => $invoice->branch_id,
                        'refund_method' => $isDamaged ? 'credit_note' : fake()->randomElement(['cash', 'credit_note']),
                    ],
                    lines: [$line],
                );
                $this->backdate($return, $this->recentDate(4), cascadeStockMovements: true);
                $created++;
            } catch (RuntimeException) {
                continue;
            }
        }

        $this->command?->info("ReturnSeeder: created {$created} of ".self::RETURN_COUNT.' targeted returns.');
    }
}
