<?php

namespace App\Http\Controllers\Epelcon;

use App\Http\Controllers\Controller;
use App\Models\Department;
use App\Models\Employee;
use App\Models\EmployeeLoan;
use App\Models\Expense;
use App\Models\Payslip;
use App\Models\Setting;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Str;

class PayrollController extends Controller
{
    public function index()
    {
        $employees = Employee::with(['department', 'loans' => fn ($q) => $q->where('status', 'active')])
            ->where('status', 'active')
            ->orderBy('name')
            ->get()
            ->map(function ($employee) {
                $employee->projected_loan_deduction = $employee->loans
                    ->sum(fn ($loan) => min((float) $loan->monthly_deduction, (float) $loan->balance));
                $employee->projected_net = (float) $employee->salary - $employee->projected_loan_deduction;

                return $employee;
            });

        $totals = [
            'gross' => $employees->sum(fn ($e) => (float) $e->salary),
            'loans' => $employees->sum('projected_loan_deduction'),
            'net' => $employees->sum('projected_net'),
        ];

        return view('epelcon.payroll.index', compact('employees', 'totals'));
    }

    public function generate(Request $request)
    {
        $request->validate(['month' => 'required|date_format:Y-m']);
        $month = $request->month;

        $employees = Employee::with(['loans' => fn ($q) => $q->where('status', 'active')])
            ->where('status', 'active')->get();

        $generated = 0;

        foreach ($employees as $employee) {
            if (Payslip::where('employee_id', $employee->id)->where('month', $month)->exists()) {
                continue;
            }

            $loanDeduction = 0.0;

            foreach ($employee->loans as $loan) {
                $deduct = min((float) $loan->monthly_deduction, (float) $loan->balance);

                if ($deduct <= 0) {
                    continue;
                }

                $newBalance = round((float) $loan->balance - $deduct, 2);
                $loan->update([
                    'balance' => $newBalance,
                    'status' => $newBalance <= 0 ? 'settled' : 'active',
                ]);

                $loanDeduction += $deduct;
            }

            $gross = (float) $employee->salary;
            $allowances = 0.0;
            $deductions = 0.0;

            Payslip::create([
                'employee_id' => $employee->id,
                'month' => $month,
                'gross' => $gross,
                'allowances' => $allowances,
                'deductions' => $deductions,
                'loan_deduction' => $loanDeduction,
                'net' => $gross + $allowances - $deductions - $loanDeduction,
                'status' => 'unpaid',
            ]);

            $generated++;
        }

        return back()->with('success', "{$generated} payslip(s) generated for {$month}.");
    }

    public function payslips(Request $request)
    {
        $payslips = Payslip::with('employee.department')
            ->when($request->filled('month'), fn ($q) => $q->where('month', $request->month))
            ->when($request->filled('status'), fn ($q) => $q->where('status', $request->status))
            ->orderByDesc('month')
            ->orderBy('id')
            ->paginate(20)->withQueryString();

        $months = Payslip::query()->distinct()->orderByDesc('month')->pluck('month');

        $summary = [
            'unpaid' => Payslip::where('status', 'unpaid')->count(),
            'unpaid_amount' => (float) Payslip::where('status', 'unpaid')->sum('net'),
        ];

        return view('epelcon.payroll.payslips', compact('payslips', 'months', 'summary'));
    }

    public function markPaid(Payslip $payslip)
    {
        if ($payslip->status === 'paid') {
            return back()->with('success', 'Payslip already paid.');
        }

        $payslip->update(['status' => 'paid', 'paid_at' => now()]);

        Expense::create([
            'code' => 'EXP-' . strtoupper(Str::random(6)),
            'category' => 'Salaries',
            'description' => "Salary {$payslip->month} — " . ($payslip->employee->name ?? 'Employee'),
            'amount' => $payslip->net,
            'expense_date' => today(),
            'payment_method' => 'transfer',
            'status' => 'paid',
            'recorded_by' => auth()->id(),
        ]);

        return back()->with('success', 'Payslip marked paid and salary expense recorded.');
    }

    public function payslip(Payslip $payslip)
    {
        $payslip->load('employee.department');
        $hotelName = Setting::get('hotel_name', 'Epelcon Hospitality');

        return view('epelcon.payroll.payslip', compact('payslip', 'hotelName'));
    }

    public function report(Request $request)
    {
        $months = collect(range(5, 0))->map(fn ($i) => now()->subMonths($i)->format('Y-m'));

        $monthly = $months->map(function ($month) {
            $slips = Payslip::where('month', $month);

            return [
                'month' => $month,
                'label' => Carbon::createFromFormat('Y-m', $month)->format('M Y'),
                'count' => (clone $slips)->count(),
                'gross' => (float) (clone $slips)->sum('gross'),
                'loan_deductions' => (float) (clone $slips)->sum('loan_deduction'),
                'net' => (float) (clone $slips)->sum('net'),
            ];
        });

        $byDepartment = Department::with(['employees' => fn ($q) => $q->where('status', 'active')])
            ->orderBy('name')->get()
            ->map(fn ($dept) => [
                'name' => $dept->name,
                'headcount' => $dept->employees->count(),
                'monthly_cost' => $dept->employees->sum(fn ($e) => (float) $e->salary),
            ]);

        $unassigned = Employee::whereNull('department_id')->where('status', 'active')->get();
        if ($unassigned->isNotEmpty()) {
            $byDepartment->push([
                'name' => 'Unassigned',
                'headcount' => $unassigned->count(),
                'monthly_cost' => $unassigned->sum(fn ($e) => (float) $e->salary),
            ]);
        }

        return view('epelcon.payroll.report', compact('monthly', 'byDepartment'));
    }
}
