/var/www/html/back/app/Services/CashFlow/ActiveTabDayService.php
<?php

namespace App\Services\CashFlow;

use App\Domain\Article\Enums\ArticleTypeEnum;
use App\Domain\Payment\Enums\PaymentStatusEnum;
use App\Domain\Payment\Enums\PaymentTypeEnum;
use App\Http\Resources\CashFlowCreditResource;
use App\Http\Resources\CashFlowCreditToMonthResource;
use App\Http\Resources\CashFlowDebitResource;
use App\Http\Resources\CashFlowDebitToMonthResource;
use App\Http\Resources\NotDistributedPaymentResource;
use App\Models\Article;
use App\Models\ArticleGroup;
use App\Models\Counterparty;
use App\Models\PaymentDistribution;
use App\Repositories\CashFlowIndex\Interfaces\PaymentDistributionsRepositoryInterface;
use App\Repositories\CashFlowIndex\Interfaces\TotalAmountRepositoryInterface;
use App\Responses\ResponseDto;
use App\Services\CashFlowService;
use Carbon\Carbon;

class ActiveTabDayService
{
    private $distributionsRepository;
    private $paymentRepository;

    public function __construct(PaymentDistributionsRepositoryInterface $paymentDistributionsRepository,
                                TotalAmountRepositoryInterface          $paymentRepository,
                                protected CashFlowService               $cashFlowService)
    {
        $this->distributionsRepository = $paymentDistributionsRepository;
        $this->paymentRepository = $paymentRepository;
    }

    public function getIndex(int $modelID, $filters)
    {
        $paymentDistributionsCredit = $this->distributionsRepository->getPaymentDistributions($modelID, $filters, ArticleTypeEnum::ARTICLE_TYPE_CREDIT->value);
        $paymentDistributionsDebit = $this->distributionsRepository->getPaymentDistributions($modelID, $filters, ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value);

        $totalAmountCreditPayment = $this->paymentRepository->getTotalAmountPayment($modelID, $filters, $credit = true);
        $totalAmountDebitPayment = $this->paymentRepository->getTotalAmountPayment($modelID, $filters, $credit = false);

        $totalAmountCashCreditPayment = $this->paymentRepository->getTotalAmountCashPayment($modelID, $filters, $credit = true, $debitType = null);
        $totalAmountCashDebitMovingPayment = $this->paymentRepository->getTotalAmountCashPayment($modelID, $filters, $credit = false, $debitType = 'cash');
        $totalAmountCashDebitCommissionPayment = $this->paymentRepository->getTotalCommissionPaymentDistribution($modelID, $filters, $debitType);

        $totalMoving = $this->paymentRepository->getTotalAmountCashPayment($modelID, $filters, $credit = false, $debitType = 'moving');

        $paymentNotDistributionCredit = $this->distributionsRepository->getNotDistributionsPayment($modelID, $filters, $credit = true);
        $paymentNotDistributionDebit = $this->distributionsRepository->getNotDistributionsPayment($modelID, $filters, $credit = false);

        $totalCash = $this->cashFlowService->getTotalCash($filters, $modelID);

        $check = array_filter($filters, function ($value) {
            return $value !== null;
        });

        if ($check) {
            $formattedDataCredit = $this->sortToDays($paymentDistributionsCredit, true, $check);
            $formattedDataDebit = $this->sortToDays($paymentDistributionsDebit, false, $check);
            $formattedTotalCash = $this->sortToDaysTotalCash($filters, $check, $modelID);
            $formattedOtherData = $this->sortToDaysOtherData($filters, $check, $modelID);
            $formattedNotDistributionCredit = $this->sortNotDistributedPaymentsToDay($paymentNotDistributionCredit, true, $check);
            $formattedNotDistributionDebit = $this->sortNotDistributedPaymentsToDay($paymentNotDistributionDebit, false, $check);
        } else {
            $formattedDataCredit = $this->sortToDays($paymentDistributionsCredit, true, $check);
            $formattedDataDebit = $this->sortToDays($paymentDistributionsDebit, false, $check);
            $formattedOtherData = $this->sortToDaysOtherData($filters, $check, $modelID);
            $formattedTotalCash = $this->sortToDaysTotalCash($filters, $check, $modelID);
            $formattedNotDistributionCredit = $this->sortNotDistributedPaymentsToDay($paymentNotDistributionCredit, true, $check);
            $formattedNotDistributionDebit = $this->sortNotDistributedPaymentsToDay($paymentNotDistributionDebit, false, $check);
        }

        $totalCredit = $this->sumTotalAmount($paymentDistributionsCredit);
        $totalDebit = $this->sumTotalAmount($paymentDistributionsDebit);

        $totalAmountToDay = $this->totalAmountToDays($formattedDataCredit, $formattedTotalCash);
        $totalAmountToDay = $this->mergeDistributedAndNotDistributedByDays($totalAmountToDay, $formattedNotDistributionCredit);

        $totalAmountToDayDebit = $this->totalAmountToDays($formattedDataDebit, $formattedOtherData);
        $totalAmountToDayDebit = $this->mergeDistributedAndNotDistributedByDays($totalAmountToDayDebit, $formattedNotDistributionDebit);

        $totalCashDetailes = $this->totalCasCreditToDay($formattedTotalCash);

        $totalCashDebit = array_sum(array_column($formattedOtherData, 'total_cash'));

        $ttlCash = $this->totalCashDetails($formattedDataDebit);
        $newFormat = $this->newFormat($filters, $check);

        $startPeriod = $this->startPeriod($formattedDataCredit, $formattedDataDebit, $formattedTotalCash, $newFormat, $formattedOtherData);
        $startCash = $this->startCash($formattedTotalCash, $formattedDataDebit);


        $lastCash = $this->newCash($startPeriod, $startCash);


        $totalCashDebitAAA = $this->getTotalCashDebit($paymentDistributionsDebit);


        $groupsWithoutArticlesCredit = ArticleGroup::where(['article_type' => 'credit', 'model_id' => $modelID])->doesntHave('articles')->get();
        $groupsWithoutArticlesDebit = ArticleGroup::where(['article_type' => 'debit', 'model_id' => $modelID])->doesntHave('articles')->get();

        return new ResponseDto(
            data: [
                'header' => [
                    'start_period' => [
                        'amount' => $startPeriod,
                        'cash' => $lastCash,
                    ]
                ],
                'credit' => [
                    'static' => [
                        'groups_without_articles' => $groupsWithoutArticlesCredit,
                        'total_amount' => $totalCredit + $totalAmountCreditPayment,
                        'total_cash' => $totalCash,
                        'articles' => CashFlowCreditResource::collection($paymentDistributionsCredit),
                        'not_distribution_payments_total_amount' => $totalAmountCreditPayment,
                        'cash' => $totalAmountCashCreditPayment,
                        'other_data' => [
                            'total_cash' => $totalCash,
                        ],
                    ],
                    'dynamic' => [
                        'total_amount' => $totalAmountToDay,
                        'total_cash' => $totalCashDetailes,
                        'articles' => $formattedDataCredit,
                        'other_data' => $formattedTotalCash,
                        'not_distribution_payments' => $formattedNotDistributionCredit,
                    ],
                ],
                'debit' => [
                    'static' => [
                        'groups_without_articles' => $groupsWithoutArticlesDebit,
                        'total_amount' => $totalDebit + $totalAmountDebitPayment,
                        'total_cash_debit' => $totalCashDebitAAA,
                        'articles' => CashFlowDebitResource::collection($paymentDistributionsDebit),
                        'not_distribution_payments_total_amount' => $totalAmountDebitPayment,
                        'other_data' => [
                            'moving' => $totalMoving,
                            'commission' => $totalAmountCashDebitCommissionPayment,
                            'cash' => $totalAmountCashDebitMovingPayment,
                        ],
                    ],
                    'dynamic' => [
                        'total_amount' => $totalAmountToDayDebit,
                        'total_cash' => $ttlCash,
                        'articles' => $formattedDataDebit,
                        'other_data' => $formattedOtherData,
                        'not_distribution_payments' => $formattedNotDistributionDebit,
                    ],
                ],
                'footer' => [
                    'end_period' => [
                        'amount' => $startPeriod,
                        'cash' => $lastCash,
                    ]
                ],
            ],
            status: true
        );
    }


    public function newCash($startPeriod, $startCash)
    {
        $result = [];
        $lastKnownBalance = null;

        foreach ($startPeriod as $date => $balance) {
            if (array_key_exists($date, $startCash)) {
                $result[$date] = $startCash[$date];
                $lastKnownBalance = $startCash[$date];
            } else {
                if ($lastKnownBalance !== null) {
                    $result[$date] = [
                        "start_balance" => $lastKnownBalance["end_balance"],
                        "end_balance" => $lastKnownBalance["end_balance"]
                    ];
                } else {
                    $result[$date] = [
                        "start_balance" => $balance["start_balance"],
                        "end_balance" => $balance["end_balance"]
                    ];
                }
            }
        }
        return $result;
    }

    public function startCash($formattedTotalCash, $formattedDataDebit)
    {
        $newCollection = [];

        foreach ($formattedTotalCash as $date => $dateData) {
            foreach ($dateData as $key => $data) {
                if ($data !== 0) {
                    if (isset($newCollection[$date])) {
                        if (!is_array($newCollection[$date])) {
                            $newCollection[$date] = [$newCollection[$date]];
                        }
                        $newCollection[$date] = array_merge($newCollection[$date], [$key => $data]);
                    } else {
                        $newCollection[$date] = [$key => $data];
                    }
                }
            }
        }

        foreach ($formattedDataDebit as $date => $dateData) {
            foreach ($dateData as $data) {
                if (isset($newCollection[$date])) {
                    if (!is_array($newCollection[$date])) {
                        $newCollection[$date] = [$newCollection[$date]];
                    }
                    $newCollection[$date] = array_merge($newCollection[$date], [$data]);
                } else {
                    $newCollection[$date] = [$data];
                }
            }
        }

        foreach ($newCollection as &$dates) {
            if (is_array($dates)) {
                ksort($dates);
            }
        }

        unset($dates);

        $collection = [];
        $previousBalance = 0;

        foreach ($newCollection as $date => $records) {
            $income = 0;
            $expense = 0;

            foreach ($records as $recordKey => $record) {
                if ((!is_object($record) && ($recordKey == 'total_cash'))) {
                    $income += $record;
                }
                if (is_object($record)) {
                    $item = $record->resolve();
                    if ($item['type'] == ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value) {
                        $expense += intval($item['total_extradition']);
                    }
                }
            }

            $startBalance = $previousBalance;
            $endBalance = $startBalance + $income - $expense;

            $collection[$date] = [
                'start_balance' => $startBalance,
                'end_balance' => $endBalance
            ];

            $previousBalance = $endBalance;
        }

        return $collection;

    }

    public function getTotalCashDebit($paymentDistributions)
    {
        $totalExtradition = 0;

        foreach ($paymentDistributions as $article) {
            foreach ($article->paymentDistributions as $distribution) {
                if ($distribution->payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value) {
                    $amount = (float)$distribution->amount;
                    $totalExtradition += $amount;
                }
            }
        }
        return $totalExtradition;
    }

    public function newFormat($filters, $check)
    {
        $paymentDistributions = PaymentDistribution::query()->with('payment')->get();
        $dailyCollection = [];

        foreach ($paymentDistributions as $distribution) {
            if (isset($distribution->payment->payment_date)) {
                $paymentDate = $distribution->payment->payment_date;
                $date = date('Y-m-d', strtotime($paymentDate));

                if (!isset($dailyCollection[$date])) {
                    $dailyCollection[$date] = [
                        'total_debit_cash' => 0,
                    ];
                }

                if ($distribution->payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) {
                    $dailyCollection[$date]['total_debit_cash'] += $distribution->amount;
                }

            }
        }

        return $dailyCollection;
    }

    public function startPeriod($formattedDataCredit, $formattedDataDebit, $formattedTotalCash, $formattedOtherData, $formattedCommission)
    {
        $newCollection = [];

        foreach ($formattedDataCredit as $date => $dateData) {
            foreach ($dateData as $data) {
                if (isset($newCollection[$date])) {
                    if (!is_array($newCollection[$date])) {
                        $newCollection[$date] = [$newCollection[$date]];
                    }
                    $newCollection[$date] = array_merge($newCollection[$date], [$data]);
                } else {
                    $newCollection[$date] = [$data];
                }
            }
        }

        foreach ($formattedDataDebit as $date => $dateData) {
            foreach ($dateData as $data) {
                if (isset($newCollection[$date])) {
                    if (!is_array($newCollection[$date])) {
                        $newCollection[$date] = [$newCollection[$date]];
                    }
                    $newCollection[$date] = array_merge($newCollection[$date], [$data]);
                } else {
                    $newCollection[$date] = [$data];
                }
            }
        }

        foreach ($formattedTotalCash as $date => $dateData) {
            foreach ($dateData as $key => $data) {
                if (isset($newCollection[$date])) {
                    if (!is_array($newCollection[$date])) {
                        $newCollection[$date] = [$newCollection[$date]];
                    }
                    $newCollection[$date] = array_merge($newCollection[$date], [$key => $data]);
                } else {
                    $newCollection[$date] = [$key => $data];
                }
            }
        }

        foreach ($formattedOtherData as $date => $dateData) {
            foreach ($dateData as $key => $data) {
                if (isset($newCollection[$date])) {
                    if (!is_array($newCollection[$date])) {
                        $newCollection[$date] = [$newCollection[$date]];
                    }
                    $newCollection[$date] = array_merge($newCollection[$date], [$key => $data]);
                } else {
                    $newCollection[$date] = [$key => $data];
                }
            }
        }

//        foreach ($formattedCommission as $date => $dateData) {
//            foreach ($dateData as $key => $data) {
//                if (isset($newCollection[$date])) {
//                    if (!is_array($newCollection[$date])) {
//                        $newCollection[$date] = [$newCollection[$date]];
//                    }
//                    $value = is_array($data) ? ($data['total_cash'] ?? null) : ($data->total_cash ?? null);
//
//                    $newCollection[$date]['total_moving'] = $value;
//                } else {
//                    $newCollection[$date] = [$key => $data];
//                }
//            }
//        }


        ksort($newCollection);

        foreach ($newCollection as &$dates) {
            if (is_array($dates)) {
                ksort($dates);
            }
        }

        unset($dates);

        $collection = [];
        $previousBalance = 0;

        foreach ($newCollection as $date => $records) {
            $income = 0;
            $expense = 0;

            foreach ($records as $recordKey => $record) {
                if ((!is_object($record) && ($recordKey == 'total_cash'))) {
                    $income += $record;
                }

                if ((!is_object($record) && ($key == 'total_moving'))) {
                    $expense += $record;
                }

                if (is_object($record)) {
                    if ($record->article->article_type == "credit") {
                        $income += (float)$record->total_amount;
                    } else {
                        $expense += (float)$record->total_amount;
                    }
                }
            }

            $startBalance = $previousBalance;
            $endBalance = $startBalance + $income - $expense;

            $collection[$date] = [
                'start_balance' => $startBalance,
                'end_balance' => $endBalance
            ];

            $previousBalance = $endBalance;
        }

        return $collection;
    }

    public function totalCashDetails($formattedDataDebit)
    {
        $dayExtradition = [];

        foreach ($formattedDataDebit as $date => $items) {
            if (!isset($quarterExtradition[$date])) {
                $quarterExtradition[$date] = [];
            }

            $totalExtradition = 0;

            foreach ($items as $item) {
                $arr = $item->toArray(request());
                $totalExtradition += $arr['total_extradition'] ?? 0;
                $dayExtradition[$date] = $totalExtradition;
            }
        }

        return $dayExtradition;
    }

    public function totalCasCreditToDay($formattedTotalCash)
    {
        $result = [];

        foreach ($formattedTotalCash as $date => $items) {
            if (isset($items['total_cash'])) {
                $cashValue = (float)$items['total_cash'];
                if (!isset($result[$date])) {
                    $result[$date] = 0;
                }
                $result[$date] += $cashValue;
            }
        }

        return $result;
    }

    public function getArticleShow($modelId, $articleId, $year, $month, $day, $filters)
    {
        $query = Article::query()
            ->where('model_id', $modelId)
            ->where('id', $articleId);

        $applyPaymentFilters = function ($query) use ($year, $month, $day, $filters) {
            $query->whereYear('payment_date', $year)
                ->whereMonth('payment_date', $month)
                ->whereDay('payment_date', $day)
                ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value);

            if (!empty($filters['date_from'])) {
                $dateFrom = $filters['date_from'];
                $dateTo = empty($filters['date_to']) ? Carbon::now() : $filters['date_to'];

                $query->whereBetween('payment_date', [$dateFrom, $dateTo]);
            }

            if (!empty($filters['accounts'])) {
                $query->whereIn('account_id', $filters['accounts']);
            }

            if (!empty($filters['payments_made'])) {
                $query->whereIn('status', $filters['payments_made']);
            }

            if (!empty($filters['cash'])) {
                $query->whereIn('payment_type', $filters['cash']);
            }
        };

        $query->whereHas('paymentDistributions.payment', $applyPaymentFilters);

        if (!empty($filters['projects'])) {
            $query->whereHas('paymentDistributions', function ($query) use ($filters) {
                $query->whereIn('project_id', $filters['projects']);
            });
        }

        $query->with([
            'paymentDistributions.project',
            'paymentDistributions' => function ($query) use ($filters, $applyPaymentFilters) {
                if (!empty($filters['projects'])) {
                    $query->whereIn('project_id', $filters['projects']);
                }
                $query->whereHas('payment', $applyPaymentFilters);
            },
            'paymentDistributions.payment' => function ($query) use ($applyPaymentFilters) {
                $applyPaymentFilters($query);
                $query->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                    ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                    ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value)
                    ->with('contragent');
            }
        ]);


        $article = $query->first();

        $counterparties = $this->getUniqueCounterparties($article);
        $article->counterparties = $counterparties;
        return $article;
    }


    public function totalAmountToDays($formattedDataCredit, $formattedTotalCash)
    {
        $result = [];

        foreach ($formattedDataCredit as $date => $items) {
            $dayTotalAmount = 0;
            foreach ($items as $item) {
                if (is_object($item) && isset($item->total_amount)) {
                    $dayTotalAmount += (float)$item->total_amount;
                }
            }
            $result[$date] = $dayTotalAmount;
        }


//        foreach ($formattedTotalCash as $date => $items) {
//            if (isset($items['total_cash'])) {
//                $cashValue = intval($items['total_cash']);
//                if (!isset($result[$date])) {
//                    $result[$date] = 0;
//                }
//                $result[$date] += $cashValue;
//            }
//        }

        return $result;
    }

    public function getArticlesGroupShow($modelId, $articleGroupId, $year, $month, $day, $filters)
    {
        $query = ArticleGroup::query()
            ->where('model_id', $modelId)
            ->where('id', $articleGroupId);

        $articlesCallback = function ($query) use ($year, $month, $day, $filters) {
            $query->has('paymentDistributions')
                ->with(['paymentDistributions' => function ($q) use ($year, $month, $day, $filters) {
                    $q->whereHas('payment', function ($p) use ($year, $month, $day) {
                        $p->whereYear('payment_date', $year)
                            ->whereMonth('payment_date', $month)
                            ->whereDay('payment_date', $day)
                            ->whereNotIn('payment_type', [
                                PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                                PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                                PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value
                            ]);
                    });

                    if (!empty($filters['projects'])) {
                        $q->whereIn('project_id', $filters['projects']);
                    }
                    if (!empty($filters['accounts'])) {
                        $q->whereHas('payment', fn($p) => $p->whereIn('account_id', $filters['accounts']));
                    }
                    if (!empty($filters['payments_made'])) {
                        $q->whereHas('payment', fn($p) => $p->whereIn('status', $filters['payments_made']));
                    }
                    if (!empty($filters['cash'])) {
                        $q->whereHas('payment', fn($p) => $p->whereIn('payment_type', $filters['cash']));
                    }
                }, 'paymentDistributions.payment' => function ($p) use ($filters) {
                    $p->with('contragent');
                    if (!empty($filters['accounts'])) {
                        $p->whereIn('account_id', $filters['accounts']);
                    }
                    if (!empty($filters['payments_made'])) {
                        $p->whereIn('status', $filters['payments_made']);
                    }
                    if (!empty($filters['cash'])) {
                        $p->whereIn('payment_type', $filters['cash']);
                    }
                }, 'paymentDistributions.project']);
        };

        $query->with(['articles' => $articlesCallback]);

        $articleGroups = $query->first();

        if (!$articleGroups) {
            return null;
        }

        $counterpartyIds = collect();
        $paymentsIds = collect();

        $articleGroups->articles->each(function ($article) use (&$counterpartyIds, &$paymentsIds) {
            $uniqueCounterparties = $article->paymentDistributions
                ->pluck('payment.contragent')
                ->filter()
                ->unique('id')
                ->values();

            $counterpartyIds = $counterpartyIds->concat($uniqueCounterparties->pluck('id'));

            $paymentsIds = $paymentsIds->concat($article->paymentDistributions->pluck('payment_id'));
        });

        $counterparties = Counterparty::query()
            ->whereIn('id', $counterpartyIds)
            ->with(['payments' => function ($q) use ($paymentsIds) {
                $q->whereIn('id', $paymentsIds)
                    ->with('distributions.project');
            }])
            ->get();

        $articleGroups->setRelation('counterparties', $counterparties);

        return $articleGroups;
    }

    public function getOtherDataShow($modelId, $year, $month, $day, $type, $filters)
    {
        $baseQuery = function ($query) use ($year, $month, $day) {
            $query->whereYear('payment_date', $year)
                ->whereMonth('payment_date', $month)
                ->whereDay('payment_date', $day)
                ->with('contragent');
        };

        $query = PaymentDistribution::query();

        $query->whereHas('payment', function ($query) use ($modelId) {
            $query->where('model_id', $modelId);
        });

        switch ($type) {
            case 'moving':
                $query
                    ->with(['payment' => function ($query) use ($baseQuery, $year, $month, $day, $modelId, $filters) {
                        $query->where(['payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, 'model_id' => $modelId])
                            ->where(function ($q) use ($year, $month, $day) {
                                $q->where(function ($qPayment) use ($year, $month, $day) {
                                    $qPayment->whereYear('payment_date', $year)
                                        ->whereMonth('payment_date', $month)
                                        ->whereDay('payment_date', $day);
                                });
                            })
                            ->with('contragent');

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

                        if (!empty($filters['projects'])) {
                            $query->whereHas('distributions', function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            })->with(['distributions' => function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            }]);
                        }

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query);

                    }])
                    ->whereHas('payment', function ($query) use ($baseQuery, $year, $month, $day, $modelId, $filters) {
                        $query->where(['payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value, 'model_id' => $modelId])
                            ->where(function ($q) use ($year, $month, $day) {
                                $q->where(function ($qPayment) use ($year, $month, $day) {
                                    $qPayment->whereYear('payment_date', $year)
                                        ->whereMonth('payment_date', $month)
                                        ->whereDay('payment_date', $day);
                                });
                            });

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

                        if (!empty($filters['projects'])) {
                            $query->whereHas('distributions', function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            })->with(['distributions' => function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            }]);
                        }

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query);

                    });
                break;

            case 'commission':
                $query->where('comission', '!=', null)
                    ->with(['payment' => function ($query) use ($baseQuery, $year, $month, $day, $modelId, $filters) {
                        $query->where('model_id', $modelId)
                            ->where(function ($q) use ($year, $month, $day) {
                                $q->where(function ($qMoving) use ($year, $month, $day) {
                                    $qMoving->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                        ->where(function ($qPayment) use ($year, $month, $day) {
                                            $qPayment->whereYear('payment_date', $year)
                                                ->whereMonth('payment_date', $month)
                                                ->whereDay('payment_date', $day);
                                        });
                                })->orWhere(function ($qOther) use ($year, $month, $day) {
                                    $qOther->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                        ->whereYear('payment_date', $year)
                                        ->whereMonth('payment_date', $month)
                                        ->whereDay('payment_date', $day);
                                });
                            })
                            ->with('contragent');

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

                        if (!empty($filters['projects'])) {
                            $query->whereHas('distributions', function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            })->with(['distributions' => function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            }]);
                        }

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query);
                    }])
                    ->whereHas('payment', function ($query) use ($baseQuery, $year, $month, $day, $modelId, $filters) {
                        $query->where('model_id', $modelId)
                            ->where(function ($q) use ($year, $month, $day) {
                                $q->where(function ($qMoving) use ($year, $month, $day) {
                                    $qMoving->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                        ->where(function ($qPayment) use ($year, $month, $day) {
                                            $qPayment->whereYear('payment_date', $year)
                                                ->whereMonth('payment_date', $month)
                                                ->whereDay('payment_date', $day);
                                        });
                                })->orWhere(function ($qOther) use ($year, $month, $day) {
                                    $qOther->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                        ->whereYear('payment_date', $year)
                                        ->whereMonth('payment_date', $month)
                                        ->whereDay('payment_date', $day);
                                });
                            });

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

                        if (!empty($filters['projects'])) {
                            $query->whereHas('distributions', function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            })->with(['distributions' => function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            }]);
                        }

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query);

                    });
                break;
            case 'cash':
                $query->where('cashbox', '!=', null)
                    ->with(['payment' => function ($query) use ($baseQuery, $modelId, $year, $month, $day, $filters) {
                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

                        if (!empty($filters['projects'])) {
                            $query->whereHas('distributions', function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            })->with(['distributions' => function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            }]);
                        }

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query);
                    }])
                    ->whereHas('payment', function ($query) use ($baseQuery, $modelId, $year, $month, $day, $filters) {

                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

                        if (!empty($filters['projects'])) {
                            $query->whereHas('distributions', function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            })->with(['distributions' => function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            }]);
                        }

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }

                        $baseQuery($query);
                    });
                break;
            case 'cash-credit':
                $query->with(['payment' => function ($query) use ($baseQuery, $modelId, $year, $month, $day, $filters) {
                    $query->where(function ($q) use ($modelId, $year, $month, $day) {
                        $q->where(function ($qReception) use ($modelId, $year, $month, $day) {
                            $qReception->where([
                                'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                                'model_id' => $modelId])
                                ->whereYear('payment_date', $year)
                                ->whereMonth('payment_date', $month)
                                ->whereDay('payment_date', $day);
                        })
                            ->orWhere(function ($qMoving) use ($modelId, $year, $month, $day) {
                                $qMoving->where([
                                    'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                                    'model_id' => $modelId,
                                    'status' => PaymentStatusEnum::STATUS_RECEIVED->value])
                                    ->whereNotNull('actual_date')
                                    ->whereYear('actual_date', $year)
                                    ->whereMonth('actual_date', $month)
                                    ->whereDay('actual_date', $day);
                            });
                    });
                    if (!empty($filters['date_from'])) {
                        $dateFrom = $filters['date_from'];
                        $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                        $query->where(function ($q) use ($dateFrom, $dateTo) {
                            $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                $qActual->whereNotNull('actual_date')
                                    ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                            })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                $qPayment->whereNull('actual_date')
                                    ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                            });
                        });
                    }

                    if (!empty($filters['projects'])) {
                        $query->whereHas('distributions', function ($query) use ($filters) {
                            $query->whereIn('project_id', $filters['projects']);
                        })->with(['distributions' => function ($query) use ($filters) {
                            $query->whereIn('project_id', $filters['projects']);
                        }]);
                    }

                    if (!empty($filters['accounts'])) {
                        $query->whereIn('account_id', $filters['accounts']);
                    }

                    if (!empty($filters['payments_made'])) {
                        $query->whereIn('status', $filters['payments_made']);
                    }

                    if (!empty($filters['cash'])) {
                        $query->whereIn('payment_type', $filters['cash']);
                    }

                    $query->with('contragent');
                }])
                    ->whereHas('payment', function ($query) use ($modelId, $year, $month, $day, $filters) {
                        $query->where(function ($q) use ($modelId, $year, $month, $day) {
                            $q->where(function ($qReception) use ($modelId, $year, $month, $day) {
                                $qReception->where([
                                    'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                                    'model_id' => $modelId])
                                    ->whereYear('payment_date', $year)
                                    ->whereMonth('payment_date', $month)
                                    ->whereDay('payment_date', $day);
                            })
                                ->orWhere(function ($qMoving) use ($modelId, $year, $month, $day) {
                                    $qMoving->where([
                                        'payment_type' => PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                                        'model_id' => $modelId,
                                        'status' => PaymentStatusEnum::STATUS_RECEIVED->value])
                                        ->whereNotNull('actual_date')
                                        ->whereYear('actual_date', $year)
                                        ->whereMonth('actual_date', $month)
                                        ->whereDay('actual_date', $day);
                                });
                        });
                        if (!empty($filters['date_from'])) {
                            $dateFrom = $filters['date_from'];
                            $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                            $query->where(function ($q) use ($dateFrom, $dateTo) {
                                $q->where(function ($qActual) use ($dateFrom, $dateTo) {
                                    $qActual->whereNotNull('actual_date')
                                        ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                                })->orWhere(function ($qPayment) use ($dateFrom, $dateTo) {
                                    $qPayment->whereNull('actual_date')
                                        ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                                });
                            });
                        }

                        if (!empty($filters['projects'])) {
                            $query->whereHas('distributions', function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            })->with(['distributions' => function ($query) use ($filters) {
                                $query->whereIn('project_id', $filters['projects']);
                            }]);
                        }

                        if (!empty($filters['accounts'])) {
                            $query->whereIn('account_id', $filters['accounts']);
                        }

                        if (!empty($filters['payments_made'])) {
                            $query->whereIn('status', $filters['payments_made']);
                        }

                        if (!empty($filters['cash'])) {
                            $query->whereIn('payment_type', $filters['cash']);
                        }
                    });
                break;
            default:
                break;
        }

        return $query->get();
    }


    public function sortToDaysTotalCash($filters, $check, $modelID)
    {
        $query = PaymentDistribution::query()
            ->whereHas('payment', function ($q) use ($modelID) {
                $q->where('model_id', $modelID);
            });

        if ($check) {
            if (!empty($filters['date_from'])) {
                $dateFrom = $filters['date_from'];
                $dateTo = !empty($filters['date_to']) ? $filters['date_to'] : Carbon::now();

                // Добавляем приемы по payment_date и перемещения по actual_date
                $query->whereHas('payment', function ($query) use ($dateFrom, $dateTo) {
                    $query->where(function ($q) use ($dateFrom, $dateTo) {
                        // Приемы по payment_date
                        $q->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                            ->whereBetween('payment_date', [$dateFrom, $dateTo]);
                    })->orWhere(function ($q2) use ($dateFrom, $dateTo) {
                        // Перемещения по actual_date
                        $q2->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                            ->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                            ->whereNotNull('actual_date')
                            ->whereBetween('actual_date', [$dateFrom, $dateTo]);
                    });
                });
            }
            if (!empty($filters['projects'])) {
                $query->whereIn('project_id', $filters['projects'])
                    ->whereHas('payment', function ($query) {
                        $query->where(function ($q) {
                            $q->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value);
                        })->orWhere(function ($q2) {
                            $q2->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                                ->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                                ->whereNotNull('actual_date');
                        });
                    });
            }

            if (!empty($filters['accounts'])) {
                $query->whereHas('payment', function ($query) use ($filters) {
                    $query->whereIn('account_id', $filters['accounts']);
                });
            }

            if (!empty($filters['payments_made'])) {
                $query->whereHas('payment', function ($query) use ($filters) {
                    $query->whereIn('status', $filters['payments_made']);
                });
            }

        } else {
            $query->whereHas('payment', function ($query) {
                $query->where(function ($q) {
                    $q->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value);
                })->orWhere(function ($q2) {
                    $q2->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)
                        ->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                        ->whereNotNull('actual_date');
                });
            });
        }

        $paymentDistributions = $query->get();

        $dailyCollection = [];

        foreach ($paymentDistributions as $distribution) {
            $payment = $distribution->payment;
            if (!$payment) continue;

            // Для приемов используем payment_date и amount
            if ($payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value && isset($payment->payment_date)) {
                $paymentDate = $payment->payment_date;
                $date = date('Y-m-d', strtotime($paymentDate));

                if (!isset($dailyCollection[$date])) {
                    $dailyCollection[$date] = [
                        'total_cash' => 0,
                    ];
                }

                $dailyCollection[$date]['total_cash'] += $distribution->amount;
            } // Для перемещений используем actual_date и cashbox
            elseif ($payment->payment_type == PaymentTypeEnum::PAYMENT_TYPE_MOVING->value
                && $payment->status == PaymentStatusEnum::STATUS_RECEIVED->value
                && isset($payment->actual_date)) {
                $paymentDate = $payment->actual_date;
                $date = date('Y-m-d', strtotime($paymentDate));

                if (!isset($dailyCollection[$date])) {
                    $dailyCollection[$date] = [
                        'total_cash' => 0,
                    ];
                }

                // Используем cashbox для перемещений
                if (isset($distribution->cashbox)) {
                    $dailyCollection[$date]['total_cash'] += $distribution->cashbox;
                }
            }
        }

        return $dailyCollection;
    }


    protected function sortToDays($paymentDistributions, $credit, $filter)
    {
        $dailyCollection = [];

        foreach ($paymentDistributions as $payment) {
            if (isset($payment->paymentDistributions)) {
                foreach ($payment->paymentDistributions as $distribution) {
                    if (isset($distribution->payment->payment_date)) {
                        $paymentDate = $distribution->payment->payment_date;

                        if (!isset($dailyCollection[$paymentDate])) {
                            $dailyCollection[$paymentDate] = [];
                        }

                        $articleId = $distribution->article_id;
                        $found = false;

                        if (($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value) &&
                            ($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)) {

                            $distribution->total_amount = $distribution->amount;

                        }

                        foreach ($dailyCollection[$paymentDate] as &$item) {
                            if ($item->article_id == $articleId) {

                                if (($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value) &&
                                    ($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_MOVING->value)) {
                                    $item->total_amount += $distribution->amount;
                                }
                                $found = true;
                                break;
                            }
                        }

                        if (!$found) {
                            if ($credit) {
                                $dailyCollection[$paymentDate][] = new CashFlowCreditToMonthResource($distribution);
                            } else {
                                $dailyCollection[$paymentDate][] = new CashFlowDebitToMonthResource($distribution);
                            }
                        }
                    }
                }
            }
        }

        ksort($dailyCollection);

        if ($filter) {
            foreach ($dailyCollection as $date => $items) {
                if (empty($items)) {
                    unset($dailyCollection[$date]);
                }
            }
        }

        return $dailyCollection;
    }

    public function getUniqueCounterparties($article)
    {
        $uniqueCounterparties = $article->paymentDistributions
            ->pluck('payment.contragent')
            ->unique('id')
            ->values();

        $counterpartyIds = $uniqueCounterparties->pluck('id')->toArray();

        $paymentsIds = PaymentDistribution::query()->where('article_id', $article->id)->get('payment_id')->toArray();

        return Counterparty::query()
            ->whereIn('id', $counterpartyIds)
            ->with(['payments' => function ($query) use ($paymentsIds) {
                $query->whereIn('id', $paymentsIds)
                    ->with('distributions');
            }])
            ->get();
    }

    public function sortToDaysOtherData($filters, $check, $modelId)
    {
        $query = PaymentDistribution::query();

        if ($check) {

            $query->whereHas('payment', function ($q) use ($filters, $modelId) {

                $q->where('model_id', $modelId);

                if (!empty($filters['date_from'])) {
                    $q->whereBetween('payment_date', [
                        $filters['date_from'],
                        $filters['date_to'] ?? Carbon::now()
                    ]);
                }

                if (!empty($filters['accounts'])) {
                    $q->whereIn('account_id', $filters['accounts']);
                }

                if (!empty($filters['payments_made'])) {
                    $q->whereIn('status', $filters['payments_made']);
                }

                if (!empty($filters['cash'])) {
                    $q->whereIn('payment_type', $filters['cash']);
                }
            });

            if (!empty($filters['projects'])) {
                $query->whereIn('project_id', $filters['projects']);
            }

            $query->with('payment');

        } else {
            $query->with('payment');
        }

        $paymentDistributions = $query->get();

        $dailyCollection = [];

        foreach ($paymentDistributions as $distribution) {
            if (isset($distribution->payment->payment_date)) {
                if ($distribution->payment->model_id == $modelId) {
                    $paymentDate = $distribution->payment->payment_date;
                    $date = date('Y-m-d', strtotime($paymentDate));

                    if (!isset($dailyCollection[$date])) {
                        $dailyCollection[$date] = [
                            'total_cash' => 0,
                            'total_commission' => 0,
                            'total_moving' => 0
                        ];
                    }

                    $dailyCollection[$date]['total_commission'] += (float) $distribution->comission;

                    if ($distribution->payment->payment_type === PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) {

                        $dailyCollection[$date]['total_cash']
                            += (float) $distribution->amount;

                        if (!is_null($distribution->cashbox)) {
                            $dailyCollection[$date]['total_moving']
                                += (float) $distribution->cashbox;
                        }
                    }
                }
            }
        }

        if ($check) {
            foreach ($dailyCollection as $key => $date) {
                if (($date['total_cash'] == 0) &&
                    ($date['total_commission'] == 0) &&
                    ($date['total_moving'] == 0)) {
                    unset($dailyCollection[$key]);
                }

                if (empty($date)) {
                    unset($dailyCollection[$key]);
                }
            }
        }


        return $dailyCollection;
    }

    public function sumTotalAmount($paymentDistributions)
    {
        $total = 0;

        foreach ($paymentDistributions as $article) {
            foreach ($article->paymentDistributions as $distribution) {
                if ($distribution->payment == null) {
                    continue;
                }

                if (($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_MOVING->value) &&
                    ($distribution->payment->payment_type != PaymentTypeEnum::PAYMENT_TYPE_ISSUEANCE->value)) {
                    $amount = (float)$distribution->amount;
                    $total += $amount;
                }
            }
        }
        return $total;
    }

    public function getIncomeAndExpensesToDayShow($modelId, $type, $year, $month, $day, array $filters = [])
    {
        $query = PaymentDistribution::query();

        $statuses = $filters['payments_made'] ?? [PaymentStatusEnum::STATUS_RECEIVED->value];

        $query->whereHas('payment', function ($query) use ($year, $month, $day, $statuses) {
            $query->whereYear('payment_date', $year)
                ->whereMonth('payment_date', $month)
                ->whereDay('payment_date', $day)
                ->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                ->where(function ($q) use ($statuses) {
                    $q->whereIn('status', $statuses)
                    ->orWhere(function ($q) {
                        $q->where('status', PaymentStatusEnum::STATUS_SENT->value)
                            ->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION_FROM_1C->value);
                    });
                });
        });

        switch ($type) {
            case 'credit':
                $query->with(['article' => function ($query) use ($modelId) {
                    $query->where([
                        'article_type' => ArticleTypeEnum::ARTICLE_TYPE_CREDIT->value,
                        'model_id' => $modelId
                    ]);
                }, 'payment' => function ($paymentQuery) {
                    $paymentQuery->where('payment_type', '!=', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value)
                        ->where(function ($q) {
                            $q->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                            ->orWhere(function ($q) {
                                $q->where('status', PaymentStatusEnum::STATUS_SENT->value)
                                    ->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION_FROM_1C->value);
                            });
                        })
                        ->with('contragent');
                }])->whereHas('article', function ($query) use ($modelId) {
                    $query->where([
                        'article_type' => ArticleTypeEnum::ARTICLE_TYPE_CREDIT->value,
                        'model_id' => $modelId
                    ]);
                });
                break;

            case 'debit':
                $query->with(['article' => function ($query) use ($modelId) {
                    $query
                        ->where([
                            'article_type' => ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value,
                            'model_id' => $modelId
                        ]);
                }, 'payment.contragent'])
                    ->whereHas('article', function ($query) use ($modelId) {
                        $query->where([
                            'article_type' => ArticleTypeEnum::ARTICLE_TYPE_DEBIT->value,
                            'model_id' => $modelId
                        ]);
                    });
                break;

            default:
                break;
        }


        return $query->get();

    }


    public function getCashIncomeToDayShow(int $modelId, int $year, int $month, int $day)
    {
        $query = PaymentDistribution::query()
            ->whereHas('payment', function ($query) use ($modelId, $year, $month, $day) {
                $query
                    ->where('model_id', $modelId)
                    ->where('status', PaymentStatusEnum::STATUS_RECEIVED->value)
                    ->whereIn('payment_type', [
                        PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                        PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                    ])
                    ->where(function ($q) use ($year, $month, $day) {

                        $q->where(function ($q) use ($year, $month, $day) {
                            $q->whereNotNull('actual_date')
                                ->whereYear('actual_date', $year)
                                ->whereMonth('actual_date', $month)
                                ->whereDay('actual_date', $day);
                        });

                        $q->orWhere(function ($q) use ($year, $month, $day) {
                            $q->whereNull('actual_date')
                                ->whereYear('payment_date', $year)
                                ->whereMonth('payment_date', $month)
                                ->whereDay('payment_date', $day);
                        });
                    });
            })
            ->with([
                'payment.contragent',
                'article',
            ]);

        $collection = $query->get();

        $collection->each(function ($distribution) {
            if (
                in_array(
                    $distribution->payment->payment_type,
                    [
                        PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value,
                        PaymentTypeEnum::PAYMENT_TYPE_MOVING->value,
                    ],
                    true
                )
            ) {
                $distribution->amount = $distribution->cashbox ?? $distribution->amount;
            }
        });

        return $collection;
    }


    public function getReceptionIncomeToDayShow($modelId, $year, $month, $day, $statuses)
    {
        $query = PaymentDistribution::query()
            ->whereHas('payment', function ($query) use ($modelId, $year, $month, $day, $statuses) {
                $query->where('model_id', $modelId)
                    ->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION->value);

                if (!empty($statuses)) {
                    $query->whereIn('status', $statuses);
                }

                $query->where(function ($q) use ($year, $month, $day) {
                    $q->where(function ($q) use ($year, $month, $day) {
                        $q->whereNotNull('actual_date')
                            ->whereYear('actual_date', $year)
                            ->whereMonth('actual_date', $month)
                            ->whereDay('actual_date', $day);
                    });
                    $q->orWhere(function ($q) use ($year, $month, $day) {
                        $q->whereNull('actual_date')
                            ->whereYear('payment_date', $year)
                            ->whereMonth('payment_date', $month)
                            ->whereDay('payment_date', $day);
                    });
                });
            })
            ->with([
                'payment.contragent',
                'article',
            ]);

        $collection = $query->get();

        $collection->each(function ($distribution) {
            $distribution->amount = $distribution->cashbox ?? $distribution->amount;
        });

        return $collection;
    }


    public function getUndistributedIncomeShowByDays($modelId, $year, $month, $day, $paymentsMade)
    {
        $query = PaymentDistribution::query()
            ->whereHas('payment', function ($query) use ($modelId, $year, $month, $day, $paymentsMade) {
                $query->where('model_id', $modelId)
                    ->where('payment_type', PaymentTypeEnum::PAYMENT_TYPE_RECEPTION_FROM_1C->value)
                    ->whereNull('article_id');

                if (!empty($paymentsMade)) {
                    $query->whereIn('status', $paymentsMade);
                }

                $query->where(function ($q) use ($year, $month, $day) {
                    $q->whereYear('payment_date', $year)
                        ->whereMonth('payment_date', $month)
                        ->whereDay('payment_date', $day);
                });
            })
            ->with([
                'payment.contragent',
                'article',
            ]);


        return $query->get();
    }


    protected function sortNotDistributedPaymentsToDay($paymentDistributions, $credit, $filter)
    {
        $dailyCollection = [];

        foreach ($paymentDistributions as $distribution) {
            if (!isset($distribution->payment->payment_date)) {
                continue;
            }
            $paymentDate = $distribution->payment->payment_date;

            if (!isset($dailyCollection[$paymentDate])) {
                $dailyCollection[$paymentDate] = [];
            }

            $amount = $credit
                ? $distribution->amount
                : $distribution->amount;

            $dailyCollection[$paymentDate]['total_amount'] = ($dailyCollection[$paymentDate]['total_amount'] ?? 0) + $amount;
        }

        ksort($dailyCollection);

        if ($filter) {
            foreach ($dailyCollection as $date => $items) {
                if (empty($items)) {
                    unset($dailyCollection[$date]);
                }
            }
        }

        return $dailyCollection;
    }


    private function mergeDistributedAndNotDistributedByDays(array $totalAmount, array $notDistributedPayments): array
    {
        foreach ($notDistributedPayments as $key => $data) {
            $amount = $data['total_amount'] ?? 0;

            if (!isset($totalAmount[$key])) {
                $totalAmount[$key] = 0;
            }

            $totalAmount[$key] += $amount;
        }

        if (!empty($totalAmount)) {
            $sumKeys = array_filter(array_keys($totalAmount), fn($k) => $k !== 'total');
            $totalAmount['total'] = array_sum(array_map(fn($k) => $totalAmount[$k], $sumKeys));
        }

        return $totalAmount;
    }

}