<?php

namespace App\Http\Services;

use App\Models\Budget;
use App\Models\Category;
use App\Models\UnitType;
use App\Enums\ModuleType;
use App\Models\Department;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class BudgetDetailService
{
  public function saveDetails(Request $request, Budget $budget, array $options = [])
  {
    $details = $request->input('details', []);
    $department = Department::active($request)->first() ?? $budget->department;

    $budgetDetailCode = $budget->code;
    $budgetDetailNumber = 0;

    if ($budget->budgetDetails()->exists()) {
      $lastDetail = $budget->budgetDetails()->latest('id')->value('code');
      if ($lastDetail && preg_match('/\/(\d+)$/', $lastDetail, $matches)) {
        $budgetDetailNumber = intval($matches[1]);
      }
    }

    $this->deleteRemovedItems($budget, $details, $options);

    $totalDebitAmount = 0;

    foreach ($details as $detailGroup) {
      $categoryId = $this->resolveCategoryId($detailGroup['category_id'], $department);

      $budgetDetailsData = [];
      $groupTotal = 0;

      foreach ($detailGroup['items'] as $item) {
        $budgetDetailNumber++;

        $itemTotalQuantity = $this->calculateItemQuantity($item, $options);

        $price = intval($item['price']);
        $total = $itemTotalQuantity * $price;
        $groupTotal += $total;

        $status = $budget->status;
        if (!empty($options['target_status'])) {
          $status = $options['target_status'];
        }
        if (!empty($item['status'])) {
          $status = $item['status'];
        }

        $budgetDetailsData[] = [
          'id' => $item['id'] ?? null,
          'budget_id' => $budget->id,
          'code' => ($item['id'] ?? null) ? null : sprintf("%s/%04d", $budgetDetailCode, $budgetDetailNumber),
          'name' => $item['name'],
          'price' => $price,
          'price_total' => $total,
          'description' => $item['description'] ?? null,
          'user_id' => $budget->user_id ?? auth()->id(),
          'status' => $status,
          'original_quantity_unit' => $item['quantity_unit'] ?? [],
          'status_message' => empty($options['is_revision']) ? null : "",
        ];
      }

      if (empty($budgetDetailsData))
        continue;

      $budgetCategory = $budget->budgetCategories()->updateOrCreate(
        ['category_id' => $categoryId],
        ['price_amount_total' => $groupTotal]
      );

      foreach ($budgetDetailsData as $detailData) {

        if (!empty($options['is_revision']) && !empty($detailData['id'])) {
          $exists = $budget->budgetDetails()->where('id', $detailData['id'])->exists();
          if (!$exists)
            continue;
        }

        $originalQuantityUnit = $detailData['original_quantity_unit'];
        unset($detailData['original_quantity_unit']);

        if (!empty($detailData['id'])) {
          unset($detailData['code']);
          unset($detailData['user_id']);
        }

        if (empty($detailData['id']) && empty($detailData['code'])) {
          $detailData['code'] = sprintf("%s/%04d", $budgetDetailCode, $budgetDetailNumber);
        }

        $budgetDetail = $budgetCategory->budgetDetails()->updateOrCreate(
          ['id' => $detailData['id'] ?? null],
          $detailData
        );

        $budgetDetail->quantityUnits()->delete();

        if (!empty($originalQuantityUnit)) {
          foreach ($originalQuantityUnit as $qu) {
            $unitTypeId = $this->resolveUnitTypeId($qu['unit_type_id'], $department);

            $budgetDetail->quantityUnits()->create([
              'unit_type_id' => $unitTypeId,
              'quantity' => $qu['quantity'],
              'user_id' => auth()->id(),
              'company_id' => $budget->company_id,
            ]);
          }
        }

        $this->createRevisionLog($request, $budgetDetail, $options);
      }
      $totalDebitAmount += $groupTotal;
    }

    $budget->update(['debit_amount' => $totalDebitAmount]);

    return $budget;
  }

  private function deleteRemovedItems(Budget $budget, array $details, array $options)
  {
    if (empty($options['is_revision'])) {


      $latestCategoryIds = collect($details)->pluck('category_id')->map(fn($id) => is_array($id) ? ($id['value'] ?? null) : $id)->filter();
      $budget->budgetCategories()->whereNotIn('category_id', $latestCategoryIds)->delete();

      $latestItemIds = collect($details)->pluck("items")->flatten(1)->pluck('id')->filter();
      $budget->budgetDetails()->whereNotIn('id', $latestItemIds)->delete();
    }
  }

  private function resolveCategoryId($categoryId, $department)
  {
    if (is_array($categoryId)) {
      if (!empty($categoryId['__isNew__'])) {
        $categoryName = $categoryId['value'];
        $category = Category::where(DB::raw("LOWER(name)"), strtolower($categoryName))->first();
        if (!$category) {
          $categoryName = str($categoryName)->title()->toString();
          $category = Category::create([
            'name' => $categoryName,
          ]);
        }

        $category->userCategories()->updateOrCreate(
          ['user_id' => auth()->id()],
          ['department_id' => $department->id]
        );
        return $category->id;
      } else {
        return $categoryId['value'];
      }
    }
    return $categoryId;
  }

  private function calculateItemQuantity($item, $options)
  {
    $itemTotalQuantity = 1;
    $hasQuantityUnit = false;

    if (!empty($item['quantity_unit']) && is_array($item['quantity_unit'])) {
      foreach ($item['quantity_unit'] as $qu) {
        $val = floatval($qu['quantity'] ?? 0);
        $itemTotalQuantity *= ($val ?: 1);
        $hasQuantityUnit = true;
      }
    }

    if (!$hasQuantityUnit) {
      $itemTotalQuantity = !empty($options['is_revision']) ? 1 : 0;
    }

    return $itemTotalQuantity;
  }

  private function resolveUnitTypeId($unitTypeId, $department)
  {
    if (is_array($unitTypeId) && !empty($unitTypeId['__isNew__'])) {
      $unitType = UnitType::where("name", $unitTypeId['value'])->first();
      if (!$unitType) {
        $unitType = UnitType::create(['name' => ucfirst($unitTypeId['value'])]);
        $unitType->userUnitType()->updateOrCreate(
          ['user_id' => auth()->id()],
          ['department_id' => $department->id]
        );
      }
      return $unitType->id;
    } elseif (is_array($unitTypeId)) {
      return $unitTypeId['value'];
    }
    return $unitTypeId;
  }

  private function createRevisionLog(Request $request, $budgetDetail, $options)
  {
    if (!empty($options['is_revision']) && !empty($options['approval_log'])) {
      $budgetDetail->load('quantityUnits.unitType');
      (new ApprovalLogService())->create($request, $budgetDetail, ModuleType::BudgetDetail, null, [
        'note' => "",
        'parent_id' => $options['approval_log']->id,
        'budget_detail_id' => $budgetDetail->id,
        'detail' => json_encode($budgetDetail)
      ]);
    }
  }
}
