<?php

namespace App\Services;

use App\Loan;
use App\Installment;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class LoanService
{
    public function issueLoan(array $data): Loan
    {
        return DB::transaction(function () use ($data) {

            /*
             |--------------------------------------------------------------------------
             | 1. Calculate Flat Interest
             |--------------------------------------------------------------------------
             */
            $loanAmount = $data['loan_amount'];
            $interestRate = $data['interest_rate']; // %
            $installments = $data['installment_count'];

            $totalInterest = ($loanAmount * $interestRate) / 100;
            $totalPayable = $loanAmount + $totalInterest;
            $installmentAmount = round($totalPayable / $installments, 2);

            /*
             |--------------------------------------------------------------------------
             | 2. Determine First Installment Date
             |--------------------------------------------------------------------------
             | User can pass first_installment_date manually
             */
            $issueDate = Carbon::parse($data['issue_date']);

            if (!empty($data['first_installment_date'])) {
                $firstDate = Carbon::parse($data['first_installment_date']);
            } else {
                $firstDate = match ($data['installment_type']) {
                    'daily'   => $issueDate->copy()->addDay(),
                    'weekly'  => $issueDate->copy()->addWeek(),
                    'monthly' => $issueDate->copy()->addMonth(),
                };
            }

            $firstInstallment = Carbon::parse($firstDate);

            switch ($data['installment_type']) {
                case 'daily':
                    $lastInstallmentDate = $firstInstallment->copy()->addDays($installments - 1);
                    break;
                case 'weekly':
                    $lastInstallmentDate = $firstInstallment->copy()->addWeeks($installments - 1);
                    break;
                case 'monthly':
                    $lastInstallmentDate = $firstInstallment->copy()->addMonths($installments - 1);
                    break;
                default:
                    $lastInstallmentDate = $firstInstallment; // fallback
            }

            /*
             |--------------------------------------------------------------------------
             | 3. Save Loan
             |--------------------------------------------------------------------------
             */
            $loan = Loan::create([
                'customer_id'            => $data['customer_id'],
                // 'loan_no'                => $data['loan_no'],
                'loan_amount'            => $loanAmount,
                'interest_rate'          => $interestRate,
                'installment_type'       => $data['installment_type'],
                'installment_count'      => $installments,
                'total_interest'         => $totalInterest,
                'total_payable'          => $totalPayable,
                'installment_amount'     => $installmentAmount,
                'issue_date'             => $issueDate,
                'first_installment_date' => $firstDate,
                'last_installment_date'  => $lastInstallmentDate, // update later
            ]);

            /*
             |--------------------------------------------------------------------------
             | 4. Generate Installment Schedule
             |--------------------------------------------------------------------------
             */
            $currentDate = $firstDate->copy();

            for ($i = 1; $i <= $installments; $i++) {

                Installment::create([
                    'loan_id'           => $loan->id,
                    'installment_no'    => $i,
                    'due_date'          => $currentDate,
                    'principal_amount'  => round($loanAmount / $installments, 2),
                    'interest_amount'   => round($totalInterest / $installments, 2),
                    'total_amount'      => $installmentAmount,
                ]);

                // Move to next date
                $currentDate = match ($data['installment_type']) {
                    'daily'   => $currentDate->addDay(),
                    'weekly'  => $currentDate->addWeek(),
                    'monthly' => $currentDate->addMonth(),
                };
            }

            /*
             |--------------------------------------------------------------------------
             | 5. Update Last Installment Date
             |--------------------------------------------------------------------------
             */
            $loan->update([
                'last_installment_date' => $currentDate->sub(
                    match ($data['installment_type']) {
                        'daily' => '1 day',
                        'weekly' => '1 week',
                        'monthly' => '1 month',
                    }
                )
            ]);

            return $loan;
        });
    }


    public function updateLoan(Loan $loan, array $data): Loan
    {
        return DB::transaction(function () use ($loan, $data) {

            // Update loan basic info
            $loan->update([
                'loan_amount'       => $data['loan_amount'],
                'interest_rate'     => $data['interest_rate'],
                'installment_type'  => $data['installment_type'],
                'installment_count' => $data['installment_count'],
                'first_installment_date' => $data['first_installment_date'] ?? $loan->first_installment_date,
            ]);

            // Recalculate totals
            $loanAmount = $data['loan_amount'];
            $interestRate = $data['interest_rate'];
            $installments = $data['installment_count'];

            $totalInterest = ($loanAmount * $interestRate) / 100;
            $totalPayable = $loanAmount + $totalInterest;
            $installmentAmount = round($totalPayable / $installments, 2);

            $loan->update([
                'total_interest'     => $totalInterest,
                'total_payable'      => $totalPayable,
                'installment_amount' => $installmentAmount,
            ]);

            // Remove pending installments (not yet paid)
            $loan->installments()->where('status', 'pending')->delete();

            // Recreate pending installments
            $firstInstallment = Carbon::parse($loan->first_installment_date);
            $currentDate = $firstInstallment->copy();

            for ($i = 1; $i <= $installments; $i++) {
                Installment::create([
                    'loan_id'           => $loan->id,
                    'installment_no'    => $i,
                    'due_date'          => $currentDate,
                    'principal_amount'  => round($loanAmount / $installments, 2),
                    'interest_amount'   => round($totalInterest / $installments, 2),
                    'total_amount'      => $installmentAmount,
                ]);

                // Move to next installment date
                $currentDate = match ($data['installment_type']) {
                    'daily'   => $currentDate->addDay(),
                    'weekly'  => $currentDate->addWeek(),
                    'monthly' => $currentDate->addMonth(),
                };
            }

            // Update last installment date
            $loan->update([
                'last_installment_date' => $currentDate->sub(
                    match ($data['installment_type']) {
                        'daily' => '1 day',
                        'weekly' => '1 week',
                        'monthly' => '1 month',
                    }
                )
            ]);

            return $loan;
        });
    }

}
