<?php

namespace App\Services\Admin\Finance;

use App\Enums\EmployeeAdvanceStatus;
use App\Models\CashAccount;
use App\Models\EmployeeAdvance;
use App\Services\Concerns\HandlesCashTransactions;
use App\Services\NotificationService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;

class EmployeeAdvanceService
{
    use HandlesCashTransactions;

    public function getAll(array $filters = []): Collection
    {
        return EmployeeAdvance::select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at')
            ->with(['employee.user.userProfile'])
            ->latest()
            ->get();
    }

    public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
    {
        return EmployeeAdvance::query()
            ->select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at')
            ->with(['employee.user.userProfile'])
            ->when($search, fn ($q) => $q->where('description', 'like', "%{$search}%"))
            ->orderBy($sort, $direction)
            ->paginate($perPage);
    }

    public function create(array $data): EmployeeAdvance
    {
        $employeeAdvance = DB::transaction(function () use ($data) {
            $employee = auth()->user()->employee;

            if (! $employee) {
                throw new \Exception('Anda tidak terdaftar sebagai karyawan.');
            }

            $cashTransaction = $this->debitCash(
                amount: $data['amount'],
                description: 'Kasbon: '.$data['description'],
            );

            return EmployeeAdvance::create([
                'cash_transaction_id' => $cashTransaction->id,
                'employee_id' => $employee->id,
                'amount' => $data['amount'],
                'description' => $data['description'],
                'due_date' => $data['due_date'],
                'status' => EmployeeAdvanceStatus::PENDING,
            ]);
        });

        $employeeAdvance->load('employee.user');

        NotificationService::notify(
            roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
            title: 'Kasbon Baru',
            body: 'Kasbon sebesar Rp '.number_format($data['amount'], 0, ',', '.')." dari {$employeeAdvance->employee->name} menunggu persetujuan".' oleh '.auth()->user()->full_name.'.',
            url: route('admin.finance.employee-advances.index'),
            additionalUser: $employeeAdvance->employee->user ?? null,
        );

        return $employeeAdvance;
    }

    public function update(EmployeeAdvance $employeeAdvance, array $data): EmployeeAdvance
    {
        return DB::transaction(function () use ($employeeAdvance, $data) {
            $cashAccount = CashAccount::firstOrFail();
            $cashTransaction = $employeeAdvance->cashTransaction;

            $oldAmount = $employeeAdvance->amount;
            $newAmount = $data['amount'];
            $difference = $newAmount - $oldAmount;

            if ($difference > 0 && $cashAccount->balance < $difference) {
                throw ValidationException::withMessages([
                    'amount' => 'Saldo tidak mencukupi.',
                ]);
            }

            $newBalance = $cashAccount->balance - $difference;
            $cashAccount->update(['balance' => $newBalance]);

            $cashTransaction->update([
                'amount' => $newAmount,
                'balance_after' => $newBalance,
                'description' => 'Kasbon: '.$data['description'],
            ]);

            $employeeAdvance->update([
                'amount' => $newAmount,
                'description' => $data['description'],
                'due_date' => $data['due_date'],
            ]);

            return $employeeAdvance;
        });
    }

    public function delete(EmployeeAdvance $employeeAdvance): bool
    {
        return DB::transaction(function () use ($employeeAdvance) {
            $cashAccount = CashAccount::firstOrFail();

            if ($employeeAdvance->status === EmployeeAdvanceStatus::PAID) {
                $newBalance = $cashAccount->balance + $employeeAdvance->amount;
                $cashAccount->update(['balance' => $newBalance]);
            }

            return $employeeAdvance->delete();
        });
    }

    public function approve(EmployeeAdvance $employeeAdvance): EmployeeAdvance
    {
        $employeeAdvance->update([
            'status' => EmployeeAdvanceStatus::APPROVED,
            'verified_by_id' => auth()->id(),
            'verified_at' => now(),
        ]);

        NotificationService::notify(
            roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
            title: 'Kasbon Disetujui',
            body: 'Kasbon sebesar Rp '.number_format($employeeAdvance->amount, 0, ',', '.').' telah disetujui'.' oleh '.auth()->user()->full_name.'.',
            url: route('admin.finance.employee-advances.index'),
            additionalUser: $employeeAdvance->employee->user ?? null,
        );

        return $employeeAdvance;
    }

    public function pay(EmployeeAdvance $employeeAdvance): EmployeeAdvance
    {
        $employeeAdvance = DB::transaction(function () use ($employeeAdvance) {
            $cashTransaction = $this->creditCash(
                amount: $employeeAdvance->amount,
                description: 'Pembayaran kasbon: '.$employeeAdvance->description,
            );

            $employeeAdvance->update([
                'status' => EmployeeAdvanceStatus::PAID,
                'paid_by_id' => auth()->id(),
                'paid_amount' => $employeeAdvance->amount,
                'paid_at' => now(),
                'repayment_cash_transaction_id' => $cashTransaction->id,
            ]);

            return $employeeAdvance;
        });

        NotificationService::notify(
            roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
            title: 'Kasbon Dibayar',
            body: 'Kasbon sebesar Rp '.number_format($employeeAdvance->amount, 0, ',', '.').' telah dibayar lunas'.' oleh '.auth()->user()->full_name.'.',
            url: route('admin.finance.employee-advances.index'),
            additionalUser: $employeeAdvance->employee->user ?? null,
        );

        return $employeeAdvance;
    }
}
