<?php

namespace App\Http\Controllers\Admin\Module;

use Inertia\Inertia;
use App\Utils\Helper;
use App\Models\Budget;
use App\Enums\BudgetType;
use App\Models\Vendor;
use App\Models\Payment;
use App\Models\UserBank;
use App\Models\UnitType;
use App\Enums\ActionType;
use App\Enums\ModuleType;
use App\Models\Attachment;
use App\Models\Transaction;
use App\Models\BudgetDetail;
use Illuminate\Http\Request;
use App\Enums\UserBankType;
use App\Enums\ActionStatusType;
use App\Enums\PaymentStatusType;
use App\Enums\AttachmentContentType;
use App\Enums\OriginStatusType;
use App\Http\Services\ApprovalLogService;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Storage;
use App\Http\Controllers\Core\BaseResourceController;

class PurchaseOrderController extends BaseResourceController
{
  protected $model = Transaction::class;

  protected function getPage(Request $request, $id = null): array
  {
    return [
      "name" => "purchase_orders",
      "inertia" => "Admin/Module/PurchaseOrder",
      "label" => "Purchase Order",
      "url" => "/admin/budgets/{$request->route('budget_id')}/purchase_orders",
      "fields" => Helper::getFormFields($this->validation($request)),
    ];
  }

  protected function validation(Request $request, $id = null): array
  {
    return [
      "validation" => [
        "budget_detail_id" => "required|exists:budget_details,id",
        "vendor_id" => "required|exists:vendors,id",
        "attachment" => "required|file|mimes:jpg,jpeg,png,webp,avif|max:2048",
        "amount" => "required|numeric",
        "name" => "required|string",
        "price" => "required|numeric",
        "description" => "nullable|string",
        "quantity_unit" => "required|array",
        "quantity_unit.*.quantity" => "required|numeric",
        "quantity_unit.*.unit_type_id" => "required|exists:unit_types,id",
      ],
      "default" => [],
    ];
  }

  public function index(Request $request)
  {
    $budget = Budget::withPaidAmount()->withPendingPayment()->find($request->route('budget_id'));

    if (!$budget) {
      return redirect()->back()->with("error", "Data anggaran tidak ditemukan");
    }

    $authorize = $this->getAuthorize($request, $budget, ActionType::Create);
    if ($authorize instanceof \Illuminate\Http\RedirectResponse)
      return $authorize;

    $page = $this->getPage($request);

    $budgetDetails = BudgetDetail::where('budget_id', $budget->id)
      ->where('status', 'approved')
      ->with('quantityUnits.unitType', 'budgetCategory.category')
      ->get();

    $budgetDetailsOptions = $budgetDetails->map(function ($detail) {
      $detail->quantity_unit = $detail->quantityUnits->map(function ($quantityUnit) {
        return [
          "quantity" => $quantityUnit->quantity,
          "unit_type_id" => $quantityUnit->unit_type_id,
        ];
      });

      $description = $detail->description ? "- {$detail->description}" : "";

      return [
        'value' => $detail->id,
        'label' => "{$detail->name} {$description}",
        'data' => $detail,
      ];
    });

    $vendors = Vendor::select(
      "id as value",
      DB::raw("CONCAT(company_name, ' - ', name) as label")
    )->where('status', OriginStatusType::Active)->get();

    return Inertia::render($page['inertia'] . "/Index", [
      'title' => $page['label'],
      'budget' => $budget,
      'budget_details' => $budgetDetailsOptions,
      'vendors' => $vendors,
      'unit_types' => UnitType::selectOptions()->get(),
      'page' => $page
    ]);
  }

  public function store(Request $request)
  {
    $request->validate($this->validation($request)['validation']);

    DB::beginTransaction();
    try {
      $budget = Budget::withPaidAmount()->find($request->route('budget_id'));

      if (!$budget) {
        return redirect()->back()->with("error", "Data anggaran tidak ditemukan");
      }

      $authorize = $this->getAuthorize($request, $budget, ActionType::Create);
      if ($authorize instanceof \Illuminate\Http\RedirectResponse)
        return $authorize;

      // Load budget detail if provided
      $budgetDetail = null;
      if ($request->budget_detail_id) {
        $budgetDetail = BudgetDetail::with('quantityUnits.unitType')->find($request->budget_detail_id);
        if (!$budgetDetail) {
          return redirect()->back()->with("error", "Data anggaran detail tidak ditemukan");
        }
      }

      $remainingAmount = $budget->paid_remaining_amount;
      $price = intval($request->price);
      $totalQuantity = 0;

      if ($request->has('quantity_unit')) {
        foreach ($request->quantity_unit as $qu) {
          $totalQuantity += intval($qu['quantity']);
        }
      }

      $priceTotal = $budgetDetail ? intval($budgetDetail->price_total) : ($price * $totalQuantity);

      if ($priceTotal > $remainingAmount) {
        return redirect()->back()->with("error", "Total PO Rp. " . number_format($priceTotal, 0, ',', '.') . " melebihi sisa dana anggaran Rp. " . number_format($remainingAmount, 0, ',', '.'));
      }

      // Generate PO code
      $lastTransaction = DB::table("transactions")->select("code")->where('type', 'purchase_order')->latest("id")->whereNotNull('code')->first();
      $code = "PO01";

      if ($lastTransaction) {
        $lastCode = explode("/", $lastTransaction->code);
        $lastCode = $lastCode[0];

        if ($lastCode) {
          $lastCode = str_replace("PO", "", $lastCode);
          $lastCode = str_pad(intval($lastCode) + 1, 2, "0", STR_PAD_LEFT);
          $code = "PO{$lastCode}";
        }
      }

      $code .= "/{$budget->code}";

      // Save transaction with pending status
      $transactionData = [
        'budget_detail_id' => $budgetDetail?->id,
        'balance_id' => $budget->balance_id,
        'user_id' => auth()->id(),
        'vendor_id' => $request->vendor_id,
        'code' => $code,
        'name' => $request->name,
        'type' => 'purchase_order',
        'description' => $request->description,
        'price' => $price,
        'price_total' => $priceTotal,
        'status' => 'pending',
        'status_message' => null,
      ];

      $transaction = Transaction::create($transactionData);

      // Save quantity units
      foreach ($request->quantity_unit as $qu) {
        $transaction->quantityUnits()->create([
          'transaction_id' => $transaction->id,
          'unit_type_id' => $qu['unit_type_id'],
          'quantity' => $qu['quantity'],
        ]);
      }

      // Upload attachment
      if ($request->file('attachment')) {
        $fileExt = $request->file('attachment')->getClientOriginalExtension();
        $safeCode = str_replace('/', '-', $transaction->code);
        $fileName = "$safeCode.$fileExt";
        $file = Storage::disk('local')->putFileAs('files/attachments/transactions', $request->file('attachment'), $fileName);
        if (!$file)
          return redirect()->back()->with('error', 'Gagal upload file');

        Attachment::create([
          'transaction_id' => $transaction->id,
          'module_type' => ModuleType::PurchaseOrder,
          'type' => AttachmentContentType::Image,
          'label' => $transaction->code,
          'value' => "/files/attachments/",
          'description' => "$transaction->name - $transaction->description",
          'path' => $file,
        ]);
      }

      // Auto-generate payment request
      $maxAmount = $remainingAmount;
      $paymentPercentage = $remainingAmount > 0 ? round(($priceTotal / $remainingAmount) * 100) : 0;

      $userBank = UserBank::where('user_id', $budget->user_id)->where('type', UserBankType::Personal)->first();
      $lastPayment = DB::table("payments")->select("code")->where('budget_id', $budget->id)->latest("id")->whereNotNull('code')->first();
      $invCode = "INV01";

      if ($lastPayment) {
        $lastInvCode = explode("/", $lastPayment->code);
        $lastInvCode = $lastInvCode[0];

        if ($lastInvCode) {
          $lastInvCode = str_replace("INV", "", $lastInvCode);
          $lastInvCode = str_pad(intval($lastInvCode) + 1, 2, "0", STR_PAD_LEFT);
          $invCode = "INV{$lastInvCode}";
        }
      }

      $invCode .= "/{$budget->code}";

      $paymentData = [
        "budget_id" => $budget->id,
        "department_id" => $budget->department_id,
        "company_id" => $budget->company_id,
        "transaction_id" => $transaction->id,
        "user_bank_id" => $userBank?->id ?? null,
        "code" => $invCode,
        "amount" => $priceTotal,
        'max_amount' => $maxAmount,
        'payment_percentage' => $paymentPercentage,
        "description" => "PO: {$transaction->name} - {$budget->name}",
        "method" => null,
        "type" => null,
        'payment_date' => now()->toDateTimeString(),
        'due_date' => now()->toDateTimeString(),
        'status' => PaymentStatusType::Pending,
      ];

      $payment = Payment::create($paymentData);
      $payment->save();

      // Create approval log and send notification to finance manager
      (new ApprovalLogService())->create($request, $payment, ModuleType::PurchaseOrder, ActionStatusType::Submit, [
        'is_finance' => true,
        'target_finance_department' => true,
        'transaction_id' => $transaction->id,
        'note' => $request->note ?? "Purchase Order: {$transaction->code}"
      ]);

      DB::commit();
      return redirect("/admin/budgets/{$budget->id}/payment_details")->with('success', "Purchase Order berhasil diajukan");
    } catch (\Exception $e) {
      DB::rollBack();
      return redirect()->back()->with('error', 'Terjadi kesalahan: ' . $e->getMessage());
    }
  }

  protected function getAuthorize(Request $request, $budget = null, $action = null)
  {
    if ($budget?->status?->value !== \App\Enums\BudgetStatusType::Approved) {
      return Helper::redirectBack("error", "Anggaran belum disetujui");
    }

    if ($budget?->type?->value !== BudgetType::PurchaseOrder) {
      return Helper::redirectBack("error", "Fitur ini hanya tersedia untuk anggaran jenis Purchase Order");
    }

    if (intval($budget?->paid_percentage ?? 0) >= 100) {
      return Helper::redirectBack("error", "Anggaran sudah terbayar penuh");
    }

    if ($budget->user_id != auth()->id()) {
      return Helper::redirectBack("error", "Anda tidak diperbolehkan mengajukan Purchase Order pada anggaran ini");
    }
  }
}
