<?php

namespace App\Modules\Payroll\Repositories;

use App\Modules\Payroll\Models\PayrollEmployeeSnapshot;
use App\Modules\Payroll\Support\PayrollPeriodStatus;
use App\Support\Lists\ListQuery;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Http\Request;
use Illuminate\Support\Collection;

class PayrollEmployeeSnapshotRepository
{
    public function deleteForPeriod(int $tenantId, int $payrollPeriodId): int
    {
        return PayrollEmployeeSnapshot::query()
            ->where('tenant_id', $tenantId)
            ->where('payroll_period_id', $payrollPeriodId)
            ->delete();
    }

    /**
     * @param  array<string, mixed>  $data
     */
    public function create(array $data): PayrollEmployeeSnapshot
    {
        return PayrollEmployeeSnapshot::query()->create($data);
    }

    public function countForPeriod(int $tenantId, int $payrollPeriodId): int
    {
        return PayrollEmployeeSnapshot::query()
            ->where('tenant_id', $tenantId)
            ->where('payroll_period_id', $payrollPeriodId)
            ->count();
    }

    public function paginateForPeriod(int $tenantId, int $payrollPeriodId, int $perPage = 50): LengthAwarePaginator
    {
        return PayrollEmployeeSnapshot::query()
            ->where('tenant_id', $tenantId)
            ->where('payroll_period_id', $payrollPeriodId)
            ->with(['employee:id,full_name,employee_code'])
            ->orderBy('employee_id')
            ->paginate($perPage)
            ->withQueryString();
    }

    public function paginateFinalizedForEmployee(int $tenantId, int $employeeId, int $perPage = 20): LengthAwarePaginator
    {
        return PayrollEmployeeSnapshot::query()
            ->where('tenant_id', $tenantId)
            ->where('employee_id', $employeeId)
            ->whereHas('period', fn ($q) => $q->where('status', PayrollPeriodStatus::FINALIZED))
            ->with([
                'period:id,tenant_id,name,start_date,end_date,status,finalized_at',
            ])
            ->orderByDesc('generated_at')
            ->paginate($perPage)
            ->withQueryString();
    }

    public function findFinalizedForTenantEmployee(int $tenantId, int $employeeId, int $snapshotId): ?PayrollEmployeeSnapshot
    {
        return PayrollEmployeeSnapshot::query()
            ->where('tenant_id', $tenantId)
            ->where('employee_id', $employeeId)
            ->whereKey($snapshotId)
            ->whereHas('period', fn ($q) => $q->where('status', PayrollPeriodStatus::FINALIZED))
            ->with([
                'employee:id,tenant_id,full_name,employee_code',
                'period:id,tenant_id,name,start_date,end_date,status,finalized_at',
            ])
            ->first();
    }

    public function findForTenant(int $tenantId, int $snapshotId): ?PayrollEmployeeSnapshot
    {
        return PayrollEmployeeSnapshot::query()
            ->where('tenant_id', $tenantId)
            ->whereKey($snapshotId)
            ->with([
                'employee:id,tenant_id,full_name,employee_code',
                'period:id,tenant_id,name,start_date,end_date,status,finalized_at',
            ])
            ->first();
    }

    public function paginateFinalizedForIndex(int $tenantId, Request $request): LengthAwarePaginator
    {
        $query = PayrollEmployeeSnapshot::query()
            ->where('tenant_id', $tenantId)
            ->whereHas('period', fn ($q) => $q->where('status', PayrollPeriodStatus::FINALIZED))
            ->with([
                'employee:id,tenant_id,full_name,employee_code',
                'period:id,tenant_id,name,start_date,end_date,status,finalized_at',
            ]);

        $term = trim((string) $request->input('q'));
        if ($term !== '') {
            $query->whereHas('employee', function ($q) use ($term): void {
                $q->where('full_name', 'like', '%'.$term.'%')
                    ->orWhere('employee_code', 'like', '%'.$term.'%');
            });
        }

        ListQuery::applyEquals($query, 'payroll_period_id', $request->input('period_id'));

        ListQuery::applySort(
            $query,
            $request->input('sort'),
            $request->input('dir'),
            [
                'generated_at' => 'generated_at',
                'gross_amount' => 'gross_amount',
            ],
            'generated_at',
            'desc',
        );

        return ListQuery::paginate($query, $request);
    }
}
