<?php

namespace App\Services\Finance;

use App\Models\PrePayment;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class PrePaymentInstallmentService
{
    public const INSTALLMENT_OPTIONS = [1, 2, 3, 6, 9, 12];

    /**
     * @return list<array{installment_number: int, amount: float, month: int, year: int, period_label: string}>
     */
    public function buildSchedule(
        float $totalAmount,
        int $installmentCount,
        int $startMonth,
        int $startYear
    ): array {
        $installmentCount = max(1, $installmentCount);
        $base = floor(($totalAmount / $installmentCount) * 100) / 100;
        $amounts = array_fill(0, $installmentCount, $base);
        $amounts[$installmentCount - 1] = round($totalAmount - ($base * ($installmentCount - 1)), 2);

        $cursor = Carbon::create($startYear, $startMonth, 1)->startOfMonth();
        $schedule = [];

        for ($i = 0; $i < $installmentCount; $i++) {
            $schedule[] = [
                'installment_number' => $i + 1,
                'amount' => $amounts[$i],
                'month' => $cursor->month,
                'year' => (int) $cursor->year,
                'period_label' => $cursor->format('M Y'),
            ];
            $cursor->addMonth();
        }

        return $schedule;
    }

    /**
     * @return list<PrePayment>
     */
    public function createPlan(
        int $companyId,
        int $userId,
        float $totalAmount,
        string $advanceDate,
        int $installmentCount,
        int $startMonth,
        int $startYear,
        ?string $notes = null
    ): array {
        $groupId = (string) Str::uuid();
        $schedule = $this->buildSchedule($totalAmount, $installmentCount, $startMonth, $startYear);
        $records = [];

        DB::transaction(function () use (
            $companyId,
            $userId,
            $totalAmount,
            $advanceDate,
            $installmentCount,
            $notes,
            $groupId,
            $schedule,
            &$records
        ) {
            foreach ($schedule as $item) {
                $records[] = PrePayment::create([
                    'company_id' => $companyId,
                    'user_id' => $userId,
                    'advance_date' => $advanceDate,
                    'installment_group_id' => $installmentCount > 1 ? $groupId : null,
                    'installment_number' => $installmentCount > 1 ? $item['installment_number'] : null,
                    'installment_count' => $installmentCount > 1 ? $installmentCount : null,
                    'total_amount' => $installmentCount > 1 ? $totalAmount : null,
                    'amount' => $item['amount'],
                    'month' => $item['month'],
                    'year' => $item['year'],
                    'status' => PrePayment::STATUS_PENDING,
                    'notes' => $notes,
                ]);
            }
        });

        return $records;
    }

    public function defaultDeductionStart(string $advanceDate): array
    {
        $start = Carbon::parse($advanceDate)->addMonth()->startOfMonth();

        return [
            'month' => $start->month,
            'year' => (int) $start->year,
        ];
    }

    public function cancelPendingGroup(PrePayment $prePayment): int
    {
        if (! $prePayment->installment_group_id) {
            if ($prePayment->status === PrePayment::STATUS_PENDING) {
                $prePayment->update(['status' => PrePayment::STATUS_CANCELLED]);

                return 1;
            }

            return 0;
        }

        return PrePayment::withoutGlobalScopes()
            ->where('installment_group_id', $prePayment->installment_group_id)
            ->where('status', PrePayment::STATUS_PENDING)
            ->update(['status' => PrePayment::STATUS_CANCELLED]);
    }
}
