<?php

namespace App\Http\Services;

use App\Models\Budget;
use App\Models\Transaction;
use App\Models\Balance;
use App\Enums\BudgetStatusType;
use Illuminate\Support\Facades\DB;
use App\Enums\TransactionStatusType;

class BalanceService
{
  public function getCalculatedBalance($id)
  {
    return Balance::select('balances.*')
      ->addSelect([
        'budget_remaining_total' => Budget::select(DB::raw("COALESCE(SUM(debit_amount), 0) - COALESCE(SUM(credit_amount), 0)"))
          ->whereColumn('budgets.balance_id', 'balances.id')
          ->where('status', BudgetStatusType::Approved),
        'transaction_remaining_total' => Transaction::select(DB::raw("COALESCE(SUM(price_total), 0)"))
          ->whereColumn('transactions.balance_id', 'balances.id')
          ->where('status', TransactionStatusType::Pending),
      ])
      ->where('id', $id)
      ->first();
  }

  public function syncBalance($budgetId, $balanceId = null)
  {
    if (empty($budgetId) && empty($balanceId)) {
      return;
    }
    $budget = null;
    if (empty($balanceId)) {
      $budget = Budget::where('id', $budgetId)->first();
      $balanceId = $budget?->balance_id;
    }

    if (!empty($balanceId)) {
      $balance = Balance::where('id', $balanceId)->lockForUpdate()->first();

      $balanceCalculated = $this->getCalculatedBalance($balanceId);
      if (!empty($balanceCalculated)) {
        $balance->debit_amount = (int) $balanceCalculated->budget_remaining_total;
        $balance->credit_amount = (int) $balanceCalculated->transaction_remaining_total;
        $balance->save();
        return $balance;
      }
    }

    if (empty($budget)) {
      return;
    }

    $balanceData = ["budget_id" => $budget->id, ...$budget->only(["company_id", "code", "user_id", "department_id", "year", "month",])];
    $balanceData["debit_amount"] = intval($budget->debit_amount);
    $balanceData["credit_amount"] = intval($budget->credit_amount);

    $defaults = [
      'credit_amount' => 0,
      'debit_amount' => 0,
    ];

    $balanceData = array_merge($defaults, $balanceData);
    foreach ($defaults as $default => $value) {
      if (empty($balanceData[$default])) {
        $balanceData[$default] = 0;
      }
    }

    $balance = Balance::create($balanceData);
    $budget->balance_id = $balance->id;
    $budget->save();

    return $balance;
  }
  public function syncAllBalance()
  {
    $budgets = Budget::whereNotNull('balance_id')->get();
    foreach ($budgets as $budget) {
      $balance = $this->getCalculatedBalance($budget->balance_id);
      if ($balance) {
        $balance->debit_amount = (int) $balance->budget_remaining_total;
        $balance->credit_amount = (int) $balance->transaction_remaining_total;
        $balance->save();
      }
    }
  }
}
