<?php

namespace App\Http\Controllers\Company\Payroll;

use App\Http\Controllers\Controller;
use App\Models\{
    Employee, PayrollBranch, PayrollDepartment, PayrollDesignation,
    PayrollProject, PayrollVoucher, Setting
};
use App\Services\PaySlipService;
use Illuminate\Http\Request;

class PaySlipController extends Controller
{
    public function __construct(private PaySlipService $service) {}

    public function index(Request $request)
    {
        $this->ensurePayrollModule();
        $this->gate('view');

        $cid = auth()->user()->company_id;
        $voucherOptions = $this->service->voucherSelectOptions($cid);
        $listFilters = $this->service->normalizeListFilters($request->all());

        $selectedVoucher = null;
        $rows = collect();
        $totalCount = 0;

        if ($request->filled('voucher_id')) {
            $selectedVoucher = $this->findVoucher((int) $request->voucher_id, $cid);
        } elseif ($voucherOptions !== []) {
            $selectedVoucher = $this->findVoucher((int) array_key_first($voucherOptions), $cid);
        }

        if ($selectedVoucher) {
            $allRows = $this->service->employeeRows($cid, $selectedVoucher, [
                'search'      => '',
                'employee_id' => 0,
                'department'  => $selectedVoucher->department ?? '',
                'designation' => $selectedVoucher->designation ?? '',
                'project'     => $selectedVoucher->project ?? '',
                'branch'      => $selectedVoucher->branch ?? '',
            ]);
            $totalCount = $allRows->count();
            $rows = $this->service->employeeRows($cid, $selectedVoucher, $listFilters);
        }

        return view('payroll.pay-slip.index', array_merge(
            compact('voucherOptions', 'selectedVoucher', 'rows', 'listFilters', 'totalCount'),
            $this->filterOptions($cid, $selectedVoucher),
        ));
    }

    public function print(Request $request, PayrollVoucher $payrollVoucher)
    {
        $this->ensurePayrollModule();
        $this->gate('view');
        $this->sameCompany($payrollVoucher);

        if ($payrollVoucher->voucher_type !== 'salary_sheet' || $payrollVoucher->status !== 'approved') {
            abort(404);
        }

        $cid = auth()->user()->company_id;
        $employeeIds = array_filter(array_map('intval', (array) $request->input('employees', [])));

        if ($request->filled('employee')) {
            $employeeIds[] = (int) $request->employee;
        }

        $employeeIds = array_values(array_unique(array_filter($employeeIds)));

        $query = $this->service->employeesQuery($cid, $payrollVoucher, $this->service->normalizeListFilters([]));

        if ($employeeIds !== []) {
            $query->whereIn('id', $employeeIds);
        }

        $employees = $query->get();

        if ($employees->isEmpty()) {
            abort(404, 'No employees found for this pay slip.');
        }

        $slips = $this->service->buildPaySlips($employees, $payrollVoucher);
        $company = auth()->user()->company;

        return view('payroll.pay-slip.print', compact('slips', 'company'));
    }

    public function email(Request $request)
    {
        $this->ensurePayrollModule();
        $this->gate('edit');

        $request->validate([
            'voucher_id'   => 'required|integer',
            'employee_ids' => 'required|array|min:1',
            'employee_ids.*' => 'integer',
        ]);

        return back()->with('info', 'Pay slip email will be sent in a future update. Use Print Selected for now.');
    }

    private function filterOptions(int $companyId, ?PayrollVoucher $voucher): array
    {
        $lookup = fn ($model) => $model::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->where('is_active', true)
            ->orderBy('name')
            ->pluck('name', 'name');

        $employeeQuery = Employee::withoutGlobalScopes()
            ->where('company_id', $companyId)
            ->whereNull('deleted_at')
            ->where('is_active', true)
            ->where('terminated_employee', false)
            ->orderBy('code')
            ->orderBy('name');

        if ($voucher) {
            $filters = $this->service->filtersFromVoucher($voucher);
            if ($filters['department'] !== '') {
                $employeeQuery->where('department', $filters['department']);
            }
            if ($filters['designation'] !== '') {
                $employeeQuery->where('designation', $filters['designation']);
            }
            if ($filters['project'] !== '') {
                $employeeQuery->where('project', $filters['project']);
            }
            if ($filters['branch'] !== '') {
                $employeeQuery->where('branch', $filters['branch']);
            }
            if ($filters['religion'] !== '') {
                $employeeQuery->where('religion', $filters['religion']);
            }
        }

        $employees = $employeeQuery->get(['id', 'code', 'name', 'display_name']);

        return [
            'departments'  => $lookup(PayrollDepartment::class),
            'designations' => $lookup(PayrollDesignation::class),
            'projects'     => $lookup(PayrollProject::class),
            'branches'     => $lookup(PayrollBranch::class),
            'employees'    => $employees->mapWithKeys(fn (Employee $emp) => [
                $emp->id => trim(($emp->code ? $emp->code . ' — ' : '') . ($emp->display_name ?: $emp->name)),
            ]),
        ];
    }

    private function findVoucher(int $id, int $companyId): ?PayrollVoucher
    {
        $voucher = PayrollVoucher::withoutGlobalScopes()->find($id);

        if (!$voucher || $voucher->company_id !== $companyId) {
            return null;
        }

        if ($voucher->voucher_type !== 'salary_sheet' || $voucher->status !== 'approved') {
            return null;
        }

        return $voucher;
    }

    private function ensurePayrollModule(): void
    {
        if (Setting::get(auth()->user()->company_id, 'use_payroll_module', '0') !== '1') {
            abort(404);
        }
    }

    private function gate(string $action = 'view'): void
    {
        if (!auth()->user()->hasPermission('payroll', $action)) {
            abort(403);
        }
    }

    private function sameCompany(PayrollVoucher $voucher): void
    {
        if ($voucher->company_id !== auth()->user()->company_id) {
            abort(403);
        }
    }
}
