<?php

namespace App\Services\Employee;

use App\Services\BaseService;
use App\Repositories\PayrollRepository;
use App\Models\EmployeePayroll;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Barryvdh\DomPDF\Facade\Pdf;

class PayrollService extends BaseService
{
    protected PayrollRepository $payrollRepository;

    public function __construct(PayrollRepository $repository)
    {
        parent::__construct($repository);
        $this->payrollRepository = $repository;
    }

    /**
     * Get payroll with employee
     */
    public function getAllWithEmployee(): Collection
    {
        return $this->payrollRepository->getWithEmployee();
    }

    /**
     * Get by employee
     */
    public function getByEmployee(int $employeeId): Collection
    {
        return $this->payrollRepository->getByEmployee($employeeId);
    }

    /**
     * Get by month
     */
    public function getByMonth(string $monthYear): Collection
    {
        return $this->payrollRepository->getByMonth($monthYear);
    }

    /**
     * Get pending payroll
     */
    public function getPending(): Collection
    {
        return $this->payrollRepository->getPending();
    }

    /**
     * Get approved payroll
     */
    public function getApproved(string $monthYear): Collection
    {
        return $this->payrollRepository->getApproved($monthYear);
    }

    /**
     * Generate payroll for employee
     */
    public function generateForEmployee(int $employeeId, string $monthYear, array $data): EmployeePayroll
    {
        return DB::transaction(function () use ($employeeId, $monthYear, $data) {
            $data['employee_id'] = $employeeId;
            $data['month_year'] = $monthYear;
            $data['status'] = 'pending';

            // Calculate net salary
            $data['net_salary'] = $this->calculateNetSalary($data);

            $payroll = $this->create($data);
            $this->logAction('Payroll generated', [
                'id' => $payroll->id,
                'employee_id' => $employeeId,
            ]);
            return $payroll;
        });
    }

    /**
     * Calculate net salary
     */
    protected function calculateNetSalary(array $data): float
    {
        $earnings = ($data['basic'] ?? 0) +
            ($data['hra'] ?? 0) +
            ($data['da'] ?? 0) +
            ($data['other_allowance'] ?? 0) +
            ($data['overtime'] ?? 0);

        $deductions = ($data['pf'] ?? 0) +
            ($data['esi'] ?? 0) +
            ($data['professional_tax'] ?? 0) +
            ($data['tds'] ?? 0) +
            ($data['other_deduction'] ?? 0);

        return $earnings - $deductions;
    }

    /**
     * Approve payroll
     */
    public function approve(int $id): EmployeePayroll
    {
        return DB::transaction(function () use ($id) {
            $payroll = $this->findByIdOrFail($id);
            $payroll->update([
                'status' => 'approved',
                'approved_by' => auth()->id(),
                'approved_at' => now(),
            ]);
            $this->logAction('Payroll approved', ['id' => $id]);
            return $payroll->fresh();
        });
    }

    /**
     * Reject payroll
     */
    public function reject(int $id, string $remarks): EmployeePayroll
    {
        return DB::transaction(function () use ($id, $remarks) {
            $payroll = $this->findByIdOrFail($id);
            $payroll->update([
                'status' => 'rejected',
                'remarks' => $remarks,
            ]);
            $this->logAction('Payroll rejected', ['id' => $id]);
            return $payroll->fresh();
        });
    }

    /**
     * Bulk approve
     */
    public function bulkApprove(array $ids): int
    {
        return DB::transaction(function () use ($ids) {
            $count = 0;
            foreach ($ids as $id) {
                $this->approve($id);
                $count++;
            }
            return $count;
        });
    }

    /**
     * Generate payslip PDF
     */
    public function generatePayslip(int $id)
    {
        $payroll = $this->findByIdWith($id, ['employee']);
        $pdf = Pdf::loadView('payroll.payslip', compact('payroll'));
        return $pdf->download("payslip-{$payroll->employee->employee_id}-{$payroll->month_year}.pdf");
    }
}
