<?php

namespace App\Jobs;

use App\Http\Controllers\PayrollController;
use App\Http\Controllers\Traits\HelperTrait;
use App\Http\Controllers\Traits\EmailTrait;
use App\Models\EmpCompanyDetails;
use App\Models\Fine;
use App\Models\LeavePackage;
use App\Models\LeaveRequest;
use App\Models\LeaveType;
use App\Models\Payroll;
use App\Models\Salary;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Http\Request;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
use Barryvdh\DomPDF\Facade\Pdf as PDF;

class GenerateAllPayrollReceiptsJob implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels, HelperTrait, EmailTrait;

    protected $customerId;
    protected $workspaceId;
    protected $userId;

    public function __construct($customerId = null, $workspaceId = null, $userId = null)
    {
        $this->customerId = $customerId;
        $this->workspaceId = $workspaceId;
        $this->userId = $userId;
    }

    public function handle()
    {
        Log::info('Payroll receipts job started', [
            'customer_id' => $this->customerId,
            'workspace_id' => $this->workspaceId,
            'user_id' => $this->userId
        ]);

        // Set the Auth user for the job context if provided
        if ($this->userId) {
            Auth::setUser(\App\Models\User::find($this->userId));
        }

        $monthString = Carbon::now()->subMonth()->format('Y-m');
        $date = Carbon::createFromFormat('Y-m', $monthString);

        // Get employees with proper customer/workspace filtering
        $employeesQuery = EmpCompanyDetails::where('del', 0)
            ->where('compeleted', 1)
            ->where('status', 1);

        if ($this->customerId && $this->workspaceId) {
            $employeesQuery->where('customer_id', $this->customerId)
                          ->where('workspace_id', $this->workspaceId);
        } else {
            // If no specific customer/workspace provided, get current user's context
            $ids = $this->getCustomerAndWorkspaceIds();
            if ($ids) {
                $employeesQuery->where('customer_id', $ids['customer_id'])
                              ->where('workspace_id', $ids['workspace_id']);
            } else {
                Log::error('No customer/workspace context available for job');
                return;
            }
        }

        $employees = $employeesQuery->get();

        $controller = app(PayrollController::class);
        $successCount = 0;
        $failures = [];

        foreach ($employees as $employee) {
            Log::info('Processing employee for payroll receipt', [
                'employee_id' => $employee->id,
                'customer_id' => $employee->customer_id,
                'workspace_id' => $employee->workspace_id
            ]);
            // Check if the employee has a salary set up for the target month
            $startOfMonth = Carbon::createFromFormat('Y-m', $monthString)->startOfMonth()->toDateString(); // 2025-07-01
            $endOfMonth = Carbon::createFromFormat('Y-m', $monthString)->endOfMonth()->toDateString();     // 2025-07-31

            $salary = Salary::where('employee_id', $employee->id)
                ->where('customer_id', $employee->customer_id)
                ->where('workspace_id', $employee->workspace_id)
                ->where('from', '<=', $endOfMonth)
                ->where('to', '>=', $startOfMonth)
                ->first();
                if (!$salary) {
                    Log::info('Skipping employee with no salary set for the month', [
                        'employee_id' => $employee->id,
                        'customer_id' => $employee->customer_id,
                        'workspace_id' => $employee->workspace_id,
                        'month' => $monthString
                    ]);
                    continue;
                }
            // Check if payroll already exists with proper filtering
            $payroll = Payroll::where('employee_id', $employee->id)
                ->where('pay_year', $date->year)
                ->where('pay_month', $date->month)
                ->where('customer_id', $employee->customer_id)
                ->where('workspace_id', $employee->workspace_id)
                ->first();

            if (!$payroll) {
                // Create a fake request to generate payroll
                $fakeReq = Request::create('/payroll/generate-selected-slips', 'POST', [
                    'employee_ids' => [$employee->id],
                    'month' => $monthString,
                ]);

                try {
                    $controller->generateSelectedSlips($fakeReq);
                } catch (ValidationException $ve) {
                    Log::warning('Skipped employee due to validation errors', [
                        'employee_id' => $employee->id,
                        'errors' => $ve->errors(),
                    ]);
                    $failures[] = $employee->id;
                    continue;
                }

                // Try to get the payroll again after generation
                $payroll = Payroll::where('employee_id', $employee->id)
                    ->where('pay_year', $date->year)
                    ->where('pay_month', $date->month)
                    ->where('customer_id', $employee->customer_id)
                    ->where('workspace_id', $employee->workspace_id)
                    ->first();
            }

            if (!$payroll) {
                Log::warning('Payroll not generated for employee after controller run', [
                    'employee_id' => $employee->id,
                ]);
                $failures[] = $employee->id;
                continue;
            }

            $this->generateReceiptPdfAndEmail($employee, $payroll);
            $successCount++;
        }

        Log::info('Payroll receipts job completed', [
            'success_count' => $successCount,
            'failures' => $failures,
            'customer_id' => $this->customerId,
            'workspace_id' => $this->workspaceId
        ]);
    }

    protected function generateReceiptPdfAndEmail($employee, $payroll)
    {
        $year = $payroll->pay_year;
        $month = $payroll->pay_month;
        $monthName = date('F', mktime(0, 0, 0, $month, 10));
        $folder = "{$monthName}_{$year}";

        // Get fines with proper customer/workspace filtering
        $fines = Fine::where('employee_id', $employee->id)
            ->where('customer_id', $employee->customer_id)
            ->where('workspace_id', $employee->workspace_id)
            ->whereYear('date', $year)
            ->whereMonth('date', $month)
            ->orderBy('date', 'desc')
            ->get();

        // Get salary with proper customer/workspace filtering
        $salary = Salary::where('employee_id', $employee->id)
            ->where('customer_id', $employee->customer_id)
            ->where('workspace_id', $employee->workspace_id)
            ->where(function ($q) use ($year, $month) {
                $period = "{$year}-" . str_pad($month, 2, '0', STR_PAD_LEFT);
                $q->where('from', '<=', $period)
                    ->where('to', '>=', $period);
            })
            ->first();

        $totalFines = $fines->where('type', 0)->sum('fine_amount');
        $totalBonuses = $fines->where('type', 1)->sum('fine_amount');
        $adjusted = $payroll->calculated_salary - $totalFines + $totalBonuses;

        $startOfMonth = Carbon::create($year, $month, 1)->startOfMonth();
        $endOfMonth = Carbon::create($year, $month, 1)->endOfMonth();

        // Get approved leaves with proper customer/workspace filtering
        $approvedLeaves = LeaveRequest::where('employee_id', $employee->id)
            ->where('customer_id', $employee->customer_id)
            ->where('workspace_id', $employee->workspace_id)
            ->where('status', 1)
            ->where(function ($q) use ($startOfMonth, $endOfMonth) {
                $q->whereBetween('from', [$startOfMonth, $endOfMonth])
                    ->orWhereBetween('to', [$startOfMonth, $endOfMonth])
                    ->orWhere(function ($q2) use ($startOfMonth, $endOfMonth) {
                        $q2->where('from', '<', $startOfMonth)
                            ->where('to', '>', $endOfMonth);
                    });
            })->get();

        $approvedLeaveDays = 0;
        $approvedLeaveHours = 0;
        foreach ($approvedLeaves as $leave) {
            $pkg = LeavePackage::find($leave->leave_package_id);
            $leaveType = $pkg ? LeaveType::find($pkg->leave_type_id) : null;
            if ($leaveType && $leaveType->leave_hours > 0) {
                $from = max($startOfMonth, \App\Models\BaseModel::safeCarbonParse($leave->from, 'leave->from'));
                $to = min($endOfMonth, \App\Models\BaseModel::safeCarbonParse($leave->to, 'leave->to'));
                $days = $from->diffInDays($to) + 1;
                $approvedLeaveDays += $days;
                $approvedLeaveHours += $days * $leaveType->leave_hours;
            }
        }
        $subject = 'Payslip Receipt - ' . date('M Y', mktime(0, 0, 0, $month, 1, $year));

        // Generate PDF
        $html = view('Emails.payslip_receipt', [
            'subject' => $subject,
            'payroll' => $payroll,
            'employee' => $employee,
            'employeeCom' => $employee,
            'pdf_path' => $payroll->pdf_path,
            'pay_month' => $payroll->pay_month,
            'pay_year' => $payroll->pay_year,
            'calculated_salary' => $payroll->calculated_salary,
            'basic_salary' => $payroll->basic_salary,
            'working_hours' => $payroll->working_hours / 60,
            'hours_spent' => $payroll->hours_spent / 60,
            'overtime_hours' => $payroll->overtime_hours / 60 ?? 0,
            'actual_working_hours' => $payroll->actual_working_hours / 60 ?? 0,
        ])->render();

        $pdf = PDF::loadHTML($html)->setPaper('a4', 'portrait');

        $path = storage_path("app/public/payroll_receipts/{$folder}");
        if (!is_dir($path)) {
            mkdir($path, 0755, true);
        }

        $empDetails = $employee->EmpPersonalDetails;
        $empName = preg_replace(
            '/[^A-Za-z0-9_]/',
            '',
            implode('_', array_filter([
                $empDetails->first_name ?? null,
                $empDetails->middle_name ?? null,
                $empDetails->last_name ?? null,
            ]))
        );
        $filename = "{$empName}_{$year}_{$month}.pdf";
        $fullPath = "{$path}/{$filename}";
        $pdf->save($fullPath);

        // Update payroll with PDF path
        $payroll->pdf_path = "payroll_receipts/{$folder}/{$filename}";
        $payroll->save();

        // Send email using the new email system
        $email = $employee->employee_email ?: $employee->email;
        if ($email) {
            try {
                $subject = 'Payslip Receipt - ' . date('M Y', mktime(0, 0, 0, $month, 1, $year));
                $params = [
                    "subject" => $subject . " | " . config('app.name'),
                    "to" => $email,
                    "msg" => view("Emails.payslip_receipt", [
                        'subject' => $subject,
                        'payroll' => $payroll,
                        'employee' => $employee,
                        'employeeCom' => $employee,
                        'pdf_path' => $payroll->pdf_path,
                        'pay_month' => $payroll->pay_month,
                        'pay_year' => $payroll->pay_year,
                        'calculated_salary' => $payroll->calculated_salary,
                        'basic_salary' => $payroll->basic_salary,
                        'working_hours' => $payroll->working_hours / 60,
                        'hours_spent' => $payroll->hours_spent  / 60,
                        'overtime_hours' => $payroll->overtime_hours  / 60 ?? 0,
                        'actual_working_hours' => $payroll->actual_working_hours  / 60 ?? 0,
                    ])->render(),
                ];

                $emailSent = $this->SendInstantEmail($params);
                
                if ($emailSent) {
                    Log::info('Payslip email sent successfully', [
                        'employee_id' => $employee->id,
                        'email' => $email,
                        'customer_id' => $employee->customer_id,
                        'workspace_id' => $employee->workspace_id
                    ]);
                } else {
                    Log::warning('Failed to send payslip email', [
                        'employee_id' => $employee->id,
                        'email' => $email,
                        'customer_id' => $employee->customer_id,
                        'workspace_id' => $employee->workspace_id
                    ]);
                }
            } catch (\Exception $e) {
                Log::error('Email sending failed', [
                    'employee_id' => $employee->id,
                    'email' => $email,
                    'error' => $e->getMessage(),
                    'customer_id' => $employee->customer_id,
                    'workspace_id' => $employee->workspace_id
                ]);
            }
        } else {
            Log::warning('No email address found for employee', [
                'employee_id' => $employee->id,
                'customer_id' => $employee->customer_id,
                'workspace_id' => $employee->workspace_id
            ]);
        }
    }
}
