<?php

namespace App\Jobs;

use App\Models\Employee;
use App\Models\SalaryPayment;
use App\Models\TerminationLog;
use Carbon\Carbon;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Mail;

class FinalPayrollCalculation implements ShouldQueue
{
    use Dispatchable, InteractsWithQueue, SerializesModels;

    protected Employee $employee;
    protected array $calculationDetails;

    /**
     * Create a new job instance.
     */
    public function __construct(Employee $employee)
    {
        $this->employee = $employee;
        $this->calculationDetails = [];
    }

    /**
     * Execute the job.
     */
    public function handle(): void
    {
        Log::info('Starting final payroll calculation', [
            'employee_id' => $this->employee->id,
            'dismissed_at' => $this->employee->dismissed_at
        ]);

        try {
            DB::transaction(function () {
                // 1. Calculate pro-rated salary
                $proRatedSalary = $this->calculateProRatedSalary();
                
                // 2. Calculate pending leave encashment
                $leaveEncashment = $this->calculateLeaveEncashment();
                
                // 3. Calculate unpaid dues (last month's salary, reimbursements)
                $unpaidDues = $this->calculateUnpaidDues();
                
                // 4. Calculate pending deductions
                $pendingDeductions = $this->calculatePendingDeductions();
                
                // 5. Calculate severance if applicable
                $severancePay = $this->calculateSeverancePay();
                
                // 6. Calculate final amount
                $finalAmount = $proRatedSalary + $leaveEncashment + $unpaidDues + $severancePay - $pendingDeductions;
                
                // 7. Create final payslip
                $finalPayslip = $this->createFinalPayslip($finalAmount, [
                    'pro_rated_salary' => $proRatedSalary,
                    'leave_encashment' => $leaveEncashment,
                    'unpaid_dues' => $unpaidDues,
                    'severance_pay' => $severancePay,
                    'deductions' => $pendingDeductions
                ]);
                
                // 8. Schedule final payment
                $this->scheduleFinalPayment($finalPayslip);
                
                // 9. Send notification to employee and HR
                $this->sendFinalPayrollNotifications($finalPayslip);
                
                // 10. Update termination log with payroll info
                $this->updateTerminationLog($finalAmount);
            });
            
        } catch (\Exception $e) {
            Log::error('Final payroll calculation failed', [
                'employee_id' => $this->employee->id,
                'error' => $e->getMessage(),
                'trace' => $e->getTraceAsString()
            ]);
            
            // Notify payroll admin about failure
            $this->notifyPayrollAdmin($e);
            
            throw $e;
        }
    }
    
    /**
     * Calculate pro-rated salary for partial month
     */
    protected function calculateProRatedSalary(): float
    {
        $monthlySalary = $this->employee->salaryEmployee->base_salary ?? 0;
        $dismissalDate = Carbon::parse($this->employee->dismissed_at);
        $startOfMonth = $dismissalDate->copy()->startOfMonth();
        $endOfMonth = $dismissalDate->copy()->endOfMonth();
        
        $daysInMonth = $endOfMonth->diffInDays($startOfMonth) + 1;
        $daysWorked = $dismissalDate->diffInDays($startOfMonth) + 1;
        
        $proRatedAmount = ($monthlySalary / $daysInMonth) * $daysWorked;
        
        $this->calculationDetails['pro_rated_salary'] = [
            'monthly_salary' => $monthlySalary,
            'days_in_month' => $daysInMonth,
            'days_worked' => $daysWorked,
            'amount' => round($proRatedAmount, 2)
        ];
        
        return round($proRatedAmount, 2);
    }
    
    /**
     * Calculate leave encashment
     */
    protected function calculateLeaveEncashment(): float
    {
        // Assuming you have a leaves table
        $pendingLeaves = DB::table('employee_leaves')
            ->where('employee_id', $this->employee->id)
            ->where('status', 'approved')
            ->where('used', false)
            ->sum('days');
            
        $dailyWage = ($this->employee->salaryEmployee->base_salary ?? 0) / 30;
        $encashmentAmount = $pendingLeaves * $dailyWage;
        
        $this->calculationDetails['leave_encashment'] = [
            'pending_leaves' => $pendingLeaves,
            'daily_wage' => $dailyWage,
            'amount' => round($encashmentAmount, 2)
        ];
        
        return round($encashmentAmount, 2);
    }
    
    /**
     * Calculate unpaid dues
     */
    protected function calculateUnpaidDues(): float
    {
        // Check for last month's unpaid salary
        $lastMonthUnpaid = DB::table('salary_payments')
            ->where('employee_id', $this->employee->id)
            ->where('status', 'pending')
            ->where('payment_date', '<', Carbon::now()->subMonth())
            ->sum('amount');
            
        // Check for reimbursements
        $pendingReimbursements = DB::table('employee_reimbursements')
            ->where('employee_id', $this->employee->id)
            ->where('status', 'approved')
            ->where('paid', false)
            ->sum('amount');
            
        $totalUnpaid = $lastMonthUnpaid + $pendingReimbursements;
        
        $this->calculationDetails['unpaid_dues'] = [
            'last_month_unpaid' => $lastMonthUnpaid,
            'pending_reimbursements' => $pendingReimbursements,
            'amount' => round($totalUnpaid, 2)
        ];
        
        return round($totalUnpaid, 2);
    }
    
    /**
     * Calculate pending deductions
     */
    protected function calculatePendingDeductions(): float
    {
        $pendingDeductions = DB::table('employee_deductions')
            ->where('employee_id', $this->employee->id)
            ->whereNull('deducted_at')
            ->where('effective_date', '<=', Carbon::now())
            ->sum('amount');
            
        $this->calculationDetails['pending_deductions'] = [
            'amount' => round($pendingDeductions, 2)
        ];
        
        return round($pendingDeductions, 2);
    }
    
    /**
     * Calculate severance pay based on tenure
     */
    protected function calculateSeverancePay(): float
    {
        $hireDate = Carbon::parse($this->employee->hire_date);
        $dismissalDate = Carbon::parse($this->employee->dismissed_at);
        $yearsOfService = $hireDate->diffInYears($dismissalDate);
        
        $monthlySalary = $this->employee->salaryEmployee->base_salary ?? 0;
        
        // Example: 2 weeks for every year of service
        $severanceAmount = ($monthlySalary / 4) * $yearsOfService;
        
        // Cap at 12 months salary
        $maxSeverance = $monthlySalary * 12;
        $severanceAmount = min($severanceAmount, $maxSeverance);
        
        $this->calculationDetails['severance_pay'] = [
            'years_of_service' => $yearsOfService,
            'monthly_salary' => $monthlySalary,
            'amount' => round($severanceAmount, 2)
        ];
        
        return round($severanceAmount, 2);
    }
    
    /**
     * Create final payslip
     */
    protected function createFinalPayslip(float $finalAmount, array $breakdown): SalaryPayment
    {
        $payslip = SalaryPayment::create([
            'employee_id' => $this->employee->id,
            'amount' => $finalAmount,
            'payment_date' => Carbon::now()->addDays(7), // Pay within 7 days
            'status' => 'pending',
            'type' => 'final_settlement',
            'payment_breakdown' => json_encode($breakdown),
            'calculation_details' => json_encode($this->calculationDetails),
            'processed_at' => now(),
            'processed_by' => 'system_automation'
        ]);
        
        Log::info('Final payslip created', [
            'employee_id' => $this->employee->id,
            'payslip_id' => $payslip->id,
            'amount' => $finalAmount
        ]);
        
        return $payslip;
    }
    
    /**
     * Schedule final payment
     */
    protected function scheduleFinalPayment(SalaryPayment $payslip): void
    {
        DB::table('salary_payment_schedules')->insert([
            'employee_id' => $this->employee->id,
            'payment_id' => $payslip->id,
            'scheduled_date' => $payslip->payment_date,
            'amount' => $payslip->amount,
            'status' => 'scheduled',
            'created_at' => now(),
            'updated_at' => now()
        ]);
        
        Log::info('Final payment scheduled', [
            'employee_id' => $this->employee->id,
            'payment_id' => $payslip->id,
            'scheduled_date' => $payslip->payment_date
        ]);
    }
    
    /**
     * Send final payroll notifications
     */
    protected function sendFinalPayrollNotifications(SalaryPayment $payslip): void
    {
        // Send to HR/Payroll department
        Mail::send('emails.final-payroll-hr', [
            'employee' => $this->employee,
            'payslip' => $payslip,
            'calculation_details' => $this->calculationDetails,
            'total_amount' => $payslip->amount
        ], function ($message) {
            $message->to(config('hr.payroll_notification_emails', 'payroll@yourcompany.com'))
                    ->subject("Final Payroll Calculation: {$this->employee->name}");
        });
        
        // Send to employee if email exists
        if ($this->employee->email) {
            Mail::send('emails.final-payroll-employee', [
                'employee' => $this->employee,
                'payslip' => $payslip,
                'breakdown' => json_decode($payslip->payment_breakdown, true)
            ], function ($message) {
                $message->to($this->employee->email)
                        ->subject("Your Final Settlement - {$this->employee->name}");
            });
        }
    }
    
    /**
     * Update termination log with payroll information
     */
    protected function updateTerminationLog(float $finalAmount): void
    {
        $terminationLog = TerminationLog::where('employee_id', $this->employee->id)
            ->where('is_reversed', false)
            ->latest()
            ->first();
            
        if ($terminationLog) {
            $metadata = $terminationLog->metadata ?? [];
            $metadata['final_payroll'] = [
                'calculated_at' => now(),
                'final_amount' => $finalAmount,
                'calculation_details' => $this->calculationDetails
            ];
            $terminationLog->update(['metadata' => $metadata]);
        }
    }
    
    /**
     * Notify payroll admin about failure
     */
    protected function notifyPayrollAdmin(\Exception $e): void
    {
        Mail::raw("Final payroll calculation failed for employee {$this->employee->id}\n\nError: {$e->getMessage()}", function ($message) {
            $message->to(config('hr.admin_emails', 'admin@yourcompany.com'))
                    ->subject('CRITICAL: Final Payroll Calculation Failed');
        });
    }
}