<?php

namespace App\Traits;

use Carbon\Carbon;
use App\Models\Application\Loan;
use Illuminate\Support\Facades\Log;

trait DashboardTrait
{
    protected function getActiveLoans($request)
    {
        $activeLoans = Loan::where([
            ['visible', true],
            ['available', true],
            ['fk_site', $request->fk_site],
            ['fk_office', $request->fk_office],
            ['is_active', true],
        ]);

        $this->filter($activeLoans, $request);

        return $activeLoans->count();
    }

    protected function getLoanTotalAmount($request, $type = null)
    {
        $activeLoans = Loan::where([
            ['visible', true],
            ['available', true],
            ['fk_site', $request->fk_site],
            ['fk_office', $request->fk_office],
            ['is_active', true],
        ]);

        $this->filter($activeLoans, $request);

        if ($type) {
            switch ($type) {
                case 'FAILS':
                    $activeLoans->whereHas('payments', function ($payments) use ($request) {
                        $payments->whereHas('status', function ($status) {
                            $status->where('statusname', 'FALLA');
                        })->when(isset($request->system_date), function ($query) use ($request) {
                            $initDate = Carbon::createFromDate($request->system_date)->subDays(2)->format('Y-m-d');
                            $endDate = Carbon::createFromDate($request->system_date)->addDays(4)->format('Y-m-d');

                            $query->whereBetween('duedate', [$initDate, $endDate]);
                        })->where([
                            ['visible', true],
                            ['available', true],
                            ['is_active', true],
                        ]);
                    });

                    return $activeLoans->sum('weeklypayment');
                case "RECOVERED":
                    $activeLoans->whereHas('payments', function ($payments) use ($request) {
                        $payments->whereHas('status', function ($status) {
                            $status->whereIn('statusname', ['RECUPERADO', 'INCOMPLETO']);
                        })->when(isset($request->system_date), function ($query) use ($request) {
                            $initDate = Carbon::createFromDate($request->system_date)->subDays(2)->format('Y-m-d');
                            $endDate = Carbon::createFromDate($request->system_date)->addDays(4)->format('Y-m-d');

                            $query->whereBetween('duedate', [$initDate, $endDate]);
                        })->where([
                            ['visible', true],
                            ['available', true],
                            ['is_active', true],
                        ]);
                    })->with(['payments' => function ($payments) use ($request) {
                        $payments->whereHas('status', function ($status) {
                            $status->whereIn('statusname', ['RECUPERADO', 'INCOMPLETO']);
                        })->when(isset($request->system_date), function ($query) use ($request) {
                            $initDate = Carbon::createFromDate($request->system_date)->subDays(2)->format('Y-m-d');
                            $endDate = Carbon::createFromDate($request->system_date)->addDays(4)->format('Y-m-d');

                            $query->whereBetween('duedate', [$initDate, $endDate]);
                        });
                    }]);

                    return $activeLoans->get()->sum(function ($loan) {
                        return $loan->payments->sum('payment');
                    });
            }
        }

        return $activeLoans->sum('loanamount');
    }

    protected function getRemainBalance($request)
    {
        $activeLoans = Loan::where([
            ['visible', true],
            ['available', true],
            ['fk_site', $request->fk_site],
            ['fk_office', $request->fk_office],
            ['is_active', true],
        ]);

        $this->filter($activeLoans, $request);

        $activeLoans->whereHas('payments', function ($payments) {
            $payments->whereNull('payment')
                ->orWhereColumn('payment', '<', 'weeklypayment')
                ->where([
                    ['visible', true],
                    ['available', true],
                    ['is_active', true]
                ]);
        });

        return $activeLoans->get()->sum(function ($loan) {
            $loanBalance = $loan->payments->sum(function ($payment) use ($loan) {
                $paymentBalance = $loan->weeklypayment;

                if ($payment->payment != 0) {
                    $paymentBalance = $loan->weeklypayment - $payment->payment;
                }

                return $paymentBalance;
            });

            if ($loan->loan_type->period === 30) {
                $loanBalance += $loan->loanamount;
            }

            return $loanBalance;
        });
    }

    protected function getMustDelivery($request, $next = false)
    {
        $current_date = $request->system_date ? Carbon::createFromDate($request->system_date) : Carbon::now();

        $system_date = $current_date->isSaturday() ?
            $current_date : ($current_date->between($current_date->copy()->next(Carbon::SATURDAY)->subDays(2), $current_date->copy()->next(Carbon::SATURDAY)->addDays(4)) ?
                $current_date->copy()->next(Carbon::SATURDAY) :
                $current_date->copy()->previous(Carbon::SATURDAY));

        $initDate = Carbon::createFromDate($system_date)->subDays(2);
        $endDate = Carbon::createFromDate($system_date)->addDays(4);

        $activeLoans = Loan::where([
            ['visible', true],
            ['available', true],
            ['fk_site', $request->fk_site],
            ['fk_office', $request->fk_office],
            ['is_active', true],
        ]);

        $this->filter($activeLoans, $request);

        $dueAmount = $activeLoans->when(Carbon::now()->between($initDate, $endDate), function ($query) {
            $query->whereHas('status', fn($status) => $status->where('statusname', 'SOLICITUD ACTIVA'));
        })->whereHas('payments', function ($query) use ($next, $initDate, $endDate) {
            $query->when($next, function ($query) use ($initDate, $endDate) {
                $initDate = (clone $initDate)->addWeek()->format('Y-m-d');
                $endDate = (clone $endDate)->addWeek()->format('Y-m-d');

                $query->whereBetween('duedate', [$initDate, $endDate])
                    ->whereHas('status', fn($status) => $status->whereNotIn('statusname', ['ADELANTADO POR RENOVACION', 'ADELANTADO']));
            }, function ($query) use ($initDate, $endDate) {
                $query->whereBetween('duedate', [$initDate->format('Y-m-d'), $endDate->format('Y-m-d')])
                    ->whereHas('status', fn($status) => $status->whereNotIn('statusname', ['ADELANTADO POR RENOVACION', 'ADELANTADO']));
            });
        })->get()->sum(function ($loan) use ($initDate, $endDate) {
            $weeklyPayment = $loan->weeklypayment;

            if ($loan->loan_type->period === 30) {
                $payments = (clone $loan)->payments;

                foreach ($payments as $payment) {
                    if (Carbon::createFromTimestamp($payment->duedate)->between($initDate->format('Y-m-d'), $endDate->format('Y-m-d'))) {
                        $lastPayment = $payment;
                        break;
                    }
                }

                if (isset($lastPayment)) {
                    if ($loan->duration === $lastPayment->paymentnumber) {
                        $weeklyPayment += $loan->loanamount;
                    }
                }
            }

            return $weeklyPayment;
        });

        return $dueAmount;
    }

    protected function getLoanData($request)
    {
        $activeLoans = Loan::where([
            ['visible', true],
            ['available', true],
            ['fk_site', $request->fk_site],
            ['fk_office', $request->fk_office],
            ['is_active', true],
        ]);

        $this->filter($activeLoans, $request, false);

        return $activeLoans->selectRaw('loandate as label, SUM(loanamount) as value')
            ->groupBy('loandate')
            ->orderBy('loandate', 'desc')
            ->limit(10)
            ->get()
            ->sortBy('label')
            ->values();
    }
    protected function getEarnings($request)
    {
        $activeLoans = Loan::where([
            ['visible', true],
            ['available', true],
            ['fk_site', $request->fk_site],
            ['fk_office', $request->fk_office],
            ['is_active', true],
        ]);

        $this->filter($activeLoans, $request, false);

        $activeLoans->with(['group', 'payments']);

        $earnings = $activeLoans->get()->groupBy('group.groupname')->map(function ($loans) {
            $result = [
                'earning' => 0,
                'fails' => 0
            ];

            foreach ($loans as $loan) {
                $earning = $loan->payments->sum('payment') - $loan->loanamount;

                $fails = $loan->payments->filter(function ($payment) {
                    return $payment->status->statusname === 'FALLA' && ($payment->payment === null || $payment->payment == 0);
                })->sum(function ($payment) use ($loan) {
                    return $loan->weeklypayment;
                });

                $incompletes = $loan->payments->filter(function ($payment) use ($loan) {
                    return $payment->status->statusname === 'INCOMPLETO' && $payment->payment > 0 && $payment->payment < $loan->weeklypayment;
                })->sum(function ($payment) use ($loan) {
                    return $loan->weeklypayment - $payment->payment;
                });

                $result['fails'] += $fails + $incompletes;
                $earning = $earning - $fails - $incompletes;

                $result['earning'] += $earning <= 0 ? 0 : $earning;
            }

            return $result;
        });

        return $earnings;
    }

    private function filter($data, $request, $flag = true)
    {
        $data->when(isset($request->system_date), function ($query) use ($request) {
            $query->where('loandate', '<=', $request->system_date);
        });

        return $data->whereHas('status', function ($staus) use ($flag) { //Active Loans
            if ($flag) {
                $activeStatus = ['SOLICITUD ACTIVA', 'SOLICITUD ATRASADA', 'SOLICITUD MOROSA'];
                $staus->whereIn('statusname', $activeStatus);
            }
        })->when(isset($request->fk_zones), function ($loans) use ($request) { //Zone Filter
            $loans->whereHas('group', function ($group) use ($request) {
                $group->whereHas('zone', function ($zone) use ($request) {
                    $zone->whereIn('id', $request->fk_zones)->where([
                        ['visible', true],
                        ['available', true],
                        ['is_active', true]
                    ]);
                })->where([
                    ['visible', true],
                    ['available', true],
                    ['is_active', true]
                ]);
            });
        })->when(isset($request->fk_groups), function ($groups) use ($request) { //Group Filter
            $groups->whereHas('group', function ($group) use ($request) {
                $group->whereIn('id', $request->fk_groups)->where([
                    ['visible', true],
                    ['available', true],
                    ['is_active', true]
                ]);
            });
        })->when(isset($request->fk_executives), function ($executives) use ($request) { //Executive Filter
            $executives->whereIn('fk_executive', $request->fk_executives);
        });
    }
}
