<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\Controller;
use App\Models\Employee;
use App\Models\EmployeeBonus;
use App\Models\UserAccount;
use App\Services\AccountLedgerService;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\Rule;

class EmployeeBonusController extends Controller
{
    protected array $bonusTypes = [
        'eid_bonus' => 'Eid Bonus',
        'festival_bonus' => 'Festival Bonus',
        'performance_bonus' => 'Performance Bonus',
        'incentive_bonus' => 'Incentive Bonus',
        'yearly_bonus' => 'Yearly Bonus',
        'other' => 'Other',
    ];

    public function index(Request $request)
    {
        $query = EmployeeBonus::query()
            ->where('user_id', auth()->id())
            ->with(['employee', 'account'])
            ->latest('bonus_date')
            ->latest('id');

        if ($request->filled('search')) {
            $search = trim($request->search);

            $query->where(function ($q) use ($search) {
                $q->where('title', 'like', "%{$search}%")
                    ->orWhere('bonus_type', 'like', "%{$search}%")
                    ->orWhere('reference_no', 'like', "%{$search}%")
                    ->orWhereHas('employee', function ($eq) use ($search) {
                        $eq->where('name', 'like', "%{$search}%")
                            ->orWhere('employee_code', 'like', "%{$search}%")
                            ->orWhere('phone', 'like', "%{$search}%");
                    });
            });
        }

        if ($request->filled('employee_id')) {
            $query->where('employee_id', $request->employee_id);
        }

        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        if ($request->filled('bonus_type')) {
            $query->where('bonus_type', $request->bonus_type);
        }

        if ($request->filled('month')) {
            $query->whereMonth('bonus_date', (int) $request->month);
        }

        if ($request->filled('year')) {
            $query->whereYear('bonus_date', (int) $request->year);
        }

        $bonuses = $query->paginate(20)->withQueryString();

        $employees = Employee::where('user_id', auth()->id())
            ->where('status', 'active')
            ->orderBy('name')
            ->get();

        $bonusTypes = $this->bonusTypes;

        return view('user.hr.bonuses.index', compact('bonuses', 'employees', 'bonusTypes'));
    }

    public function create()
    {
        $employees = Employee::where('user_id', auth()->id())
            ->where('status', 'active')
            ->orderBy('name')
            ->get();

        $bonusTypes = $this->bonusTypes;

        return view('user.hr.bonuses.create', compact('employees', 'bonusTypes'));
    }

    public function store(Request $request)
    {
        $validated = $request->validate([
            'employee_id' => ['required', 'integer'],
            'bonus_type' => ['required', 'string', Rule::in(array_keys($this->bonusTypes))],
            'title' => ['required', 'string', 'max:255'],
            'amount' => ['required', 'numeric', 'min:0.01'],
            'bonus_date' => ['required', 'date'],
            'note' => ['nullable', 'string'],
        ]);

        $employee = Employee::where('user_id', auth()->id())
            ->where('status', 'active')
            ->findOrFail($validated['employee_id']);

        DB::transaction(function () use ($validated, $employee) {
            EmployeeBonus::create([
                'user_id' => auth()->id(),
                'employee_id' => $employee->id,
                'bonus_type' => $validated['bonus_type'],
                'title' => $validated['title'],
                'amount' => $validated['amount'],
                'bonus_date' => $validated['bonus_date'],
                'status' => 'unpaid',
                'note' => $validated['note'] ?? null,
            ]);
        });

        $message = __('Employee_Bonus_Controller.bonus_created_successfully');

        return redirect()
            ->route('user.hr.bonuses.index')
            ->with('toast_success', $message)
            ->with('ok', $message);
    }

    public function show($id)
    {
        $bonus = EmployeeBonus::where('user_id', auth()->id())
            ->with(['employee', 'account'])
            ->findOrFail($id);

        return view('user.hr.bonuses.show', compact('bonus'));
    }

    public function edit($id)
    {
        $bonus = EmployeeBonus::where('user_id', auth()->id())->findOrFail($id);

        if ($bonus->status === 'paid') {
            $message = __('Employee_Bonus_Controller.paid_bonus_cannot_be_edited');

            return redirect()
                ->route('user.hr.bonuses.show', $bonus->id)
                ->with('toast_error', $message)
                ->with('warning', $message);
        }

        $employees = Employee::where('user_id', auth()->id())
            ->where('status', 'active')
            ->orderBy('name')
            ->get();

        $bonusTypes = $this->bonusTypes;

        return view('user.hr.bonuses.edit', compact('bonus', 'employees', 'bonusTypes'));
    }

    public function update(Request $request, $id)
    {
        $bonus = EmployeeBonus::where('user_id', auth()->id())->findOrFail($id);

        if ($bonus->status === 'paid') {
            $message = __('Employee_Bonus_Controller.paid_bonus_cannot_be_edited');

            return redirect()
                ->route('user.hr.bonuses.show', $bonus->id)
                ->with('toast_error', $message)
                ->with('warning', $message);
        }

        $validated = $request->validate([
            'employee_id' => ['required', 'integer'],
            'bonus_type' => ['required', 'string', Rule::in(array_keys($this->bonusTypes))],
            'title' => ['required', 'string', 'max:255'],
            'amount' => ['required', 'numeric', 'min:0.01'],
            'bonus_date' => ['required', 'date'],
            'note' => ['nullable', 'string'],
        ]);

        $employee = Employee::where('user_id', auth()->id())
            ->where('status', 'active')
            ->findOrFail($validated['employee_id']);

        DB::transaction(function () use ($validated, $employee, $bonus) {
            $bonus->update([
                'employee_id' => $employee->id,
                'bonus_type' => $validated['bonus_type'],
                'title' => $validated['title'],
                'amount' => $validated['amount'],
                'bonus_date' => $validated['bonus_date'],
                'note' => $validated['note'] ?? null,
            ]);
        });

        $message = __('Employee_Bonus_Controller.bonus_updated_successfully');

        return redirect()
            ->route('user.hr.bonuses.index')
            ->with('toast_success', $message)
            ->with('ok', $message);
    }

    public function payForm($id)
    {
        $bonus = EmployeeBonus::where('user_id', auth()->id())
            ->with('employee')
            ->findOrFail($id);

        if ($bonus->status === 'paid') {
            $message = __('Employee_Bonus_Controller.bonus_already_paid');

            return redirect()
                ->route('user.hr.bonuses.show', $bonus->id)
                ->with('toast_error', $message)
                ->with('warning', $message);
        }

        $accounts = UserAccount::where('user_id', auth()->id())
            ->where('status', 'active')
            ->orderBy('name')
            ->get();

        return view('user.hr.bonuses.pay', compact('bonus', 'accounts'));
    }

    public function pay(Request $request, $id)
    {
        $bonus = EmployeeBonus::where('user_id', auth()->id())
            ->with('employee')
            ->findOrFail($id);

        if ($bonus->status === 'paid') {
            $message = __('Employee_Bonus_Controller.bonus_already_paid');

            return redirect()
                ->route('user.hr.bonuses.show', $bonus->id)
                ->with('toast_error', $message)
                ->with('warning', $message);
        }

        $validated = $request->validate([
            'user_account_id' => ['required', 'integer', 'exists:user_accounts,id'],
            'payment_method' => ['required', 'string', 'max:50'],
            'reference_no' => ['nullable', 'string', 'max:255'],
            'note' => ['nullable', 'string'],
        ]);

        $account = UserAccount::where('user_id', auth()->id())
            ->where('status', 'active')
            ->findOrFail($validated['user_account_id']);

        DB::transaction(function () use ($validated, $bonus, $account) {
            $paidAt = now();

            $bonus->update([
                'status' => 'paid',
                'paid_at' => $paidAt,
                'user_account_id' => $account->id,
                'payment_method' => $validated['payment_method'],
                'reference_no' => $validated['reference_no'] ?? null,
                'note' => $validated['note'] ?? $bonus->note,
            ]);

            AccountLedgerService::post(
                userId: auth()->id(),
                accountId: $account->id,
                type: 'employee_bonus',
                referenceType: 'employee_bonus',
                referenceId: $bonus->id,
                debit: 0,
                credit: (float) $bonus->amount,
                description: __('Employee_Bonus_Controller.employee_bonus_paid') . ': ' . ($bonus->employee->name ?? __('Employee_Bonus_Controller.employee')) . ' - ' . $bonus->title,
                trxNo: $validated['reference_no'] ?? null,
                postedAt: $paidAt->toDateString()
            );
        });

        $message = __('Employee_Bonus_Controller.bonus_paid_successfully');

        return redirect()
            ->route('user.hr.bonuses.show', $bonus->id)
            ->with('toast_success', $message)
            ->with('ok', $message);
    }

    public function report(Request $request)
    {
        $query = EmployeeBonus::query()
            ->where('user_id', auth()->id())
            ->with(['employee', 'account'])
            ->latest('bonus_date')
            ->latest('id');

        if ($request->filled('month')) {
            $query->whereMonth('bonus_date', (int) $request->month);
        }

        if ($request->filled('year')) {
            $query->whereYear('bonus_date', (int) $request->year);
        }

        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }

        $bonuses = $query->paginate(30)->withQueryString();

        $summary = [
            'total_bonus' => (clone $query)->sum('amount'),
            'paid_bonus' => (clone $query)->where('status', 'paid')->sum('amount'),
            'unpaid_bonus' => (clone $query)->where('status', 'unpaid')->sum('amount'),
        ];

        return view('user.hr.bonuses.report', compact('bonuses', 'summary'));
    }

    public function destroy($id)
    {
        $bonus = EmployeeBonus::where('user_id', auth()->id())->findOrFail($id);

        if ($bonus->status === 'paid') {
            $message = __('Employee_Bonus_Controller.paid_bonus_cannot_be_deleted');

            return redirect()
                ->route('user.hr.bonuses.index')
                ->with('toast_error', $message)
                ->with('warning', $message);
        }

        DB::transaction(function () use ($bonus) {
            $bonus->delete();
        });

        $message = __('Employee_Bonus_Controller.bonus_deleted_successfully');

        return redirect()
            ->route('user.hr.bonuses.index')
            ->with('toast_success', $message)
            ->with('ok', $message);
    }
}