<?php

namespace App\Http\Controllers\Portal;

use App\Http\Controllers\Controller;
use App\Http\Requests\CreateCompanyEmployeeRequest;
use App\Http\Requests\StoreBeneficiariesRequest;
use App\Http\Requests\SubmitNinRequest;
use App\Models\AuditLog;
use App\Models\Beneficiary;
use App\Models\Company;
use App\Models\CompanyEmployee;
use App\Services\AuditService;
use App\Services\CompanyEmployeeService;
use App\Services\NinEncryptionService;
use App\Services\NinVerificationApiService;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Illuminate\Validation\ValidationException;

class CompanyEmployeeController extends Controller
{
    public function __construct(
        private readonly CompanyEmployeeService $companyEmployeeService,
        private readonly NinEncryptionService $ninEncryptionService,
        private readonly NinVerificationApiService $ninVerificationApiService,
        private readonly AuditService $auditService,
    ) {}

    /**
     * Store a newly created company employee.
     */
    public function store(CreateCompanyEmployeeRequest $request): JsonResponse
    {
        try {
            // Determine company_id based on authenticated user type
            $companyId = $this->getCompanyId($request, $request->user());

            if (!$companyId) {
                return response()->json([
                    'success' => false,
                    'message' => 'Your account is not associated with a company. Please contact support.',
                ], 403);
            }

            // Split name into first_name and last_name if needed
            $data = $request->validated();
            if (!isset($data['first_name']) || !isset($data['last_name'])) {
                // This shouldn't happen with proper validation, but just in case
                throw ValidationException::withMessages([
                    'name' => ['First name and last name are required.'],
                ]);
            }

            $employee = $this->companyEmployeeService->createEmployee($data, $companyId);

            $actorUser = $request->user();
            $this->auditService->success(
                AuditLog::ACTION_EMPLOYEE_CREATED,
                AuditLog::ACTOR_PORTAL_USER,
                $actorUser->id,
                $actorUser->email,
                'CompanyEmployee', $employee->id,
                ['employee_name' => $employee->full_name, 'company_id' => $companyId],
                $request->ip(),
            );

            return response()->json([
                'success' => true,
                'message' => 'Employee created successfully. Invitation email sent.',
                'data' => [
                    'id' => $employee->id,
                    'first_name' => $employee->first_name,
                    'last_name' => $employee->last_name,
                    'full_name' => $employee->full_name,
                    'email' => $employee->email,
                    'employment_status' => $employee->employment_status,
                    'has_portal_access' => $employee->hasPortalAccess(),
                    'has_submitted_nin' => $employee->hasSubmittedNin(),
                    'is_nin_verified' => $employee->isNinVerified(),
                    'is_validated' => $employee->is_validated ?? false,
                    'created_at' => $employee->created_at->toIso8601String(),
                ],
            ], 201);
        } catch (ValidationException $e) {
            throw $e;
        } catch (\Exception $e) {
            Log::error('Error creating company employee: ' . $e->getMessage(), [
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
                'request_data' => $request->validated(),
            ]);
            return response()->json([
                'success' => false,
                'message' => 'An error occurred while creating the employee.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Display a listing of employees (paginated, with search and filters).
     */
    public function index(): JsonResponse
    {
        try {
            $perPage = (int) request()->input('per_page', 15);
            $perPage = min(max($perPage, 1), 100); // Between 1 and 100

            // Extract search and filter parameters
            $filters = [
                'search' => request()->input('search'),
                'employment_status' => request()->input('employment_status'),
                'nin_verified' => request()->input('nin_verified'),
            ];

            // Check if user is system admin or company admin
            if ($this->isSystemAdmin()) {
                // System admin sees all employees
                $employees = $this->companyEmployeeService->getAllEmployees($perPage, $filters);
            } else {
                // Company admin sees only their company's employees
                $user = request()->user();
                $companyId = $this->getCompanyIdForUser($user);

                if (!$companyId) {
                    return response()->json([
                        'success' => false,
                        'message' => 'Your account is not associated with a company. Please contact support.',
                    ], 403);
                }

                $employees = $this->companyEmployeeService->getEmployeesByCompany($companyId, $perPage, $filters);
            }

            return response()->json([
                'success' => true,
                'data' => $employees->items() ? collect($employees->items())->map(function ($employee) {
                    $data = [
                        'id' => $employee->id,
                        'first_name' => $employee->first_name,
                        'last_name' => $employee->last_name,
                        'full_name' => $employee->full_name,
                        'email' => $employee->email,
                        'phone' => $employee->phone,
                        'employee_number' => $employee->employee_number,
                        'department' => $employee->department,
                        'position' => $employee->position,
                        'employment_status' => $employee->employment_status,
                        'has_portal_access' => $employee->hasPortalAccess(),
                        'has_submitted_nin' => $employee->hasSubmittedNin(),
                        'is_nin_verified' => $employee->isNinVerified(),
                        'is_validated' => $employee->is_validated ?? false,
                        'hire_date' => $employee->hire_date?->toDateString(),
                        'created_at' => $employee->created_at->toIso8601String(),
                    ];

                    // Include NIN data if verified
                    if ($employee->isNinVerified()) {
                        $data['nin_data'] = [
                            'firstname' => $employee->nin_firstname,
                            'middlename' => $employee->nin_middlename,
                            'surname' => $employee->nin_surname,
                            'phone' => $employee->nin_phone,
                            'gender' => $employee->nin_gender,
                            'birthdate' => $employee->nin_birthdate?->format('Y-m-d'),
                            'birth_info' => [
                                'country' => $employee->nin_birthcountry,
                                'state' => $employee->nin_birthstate,
                                'lga' => $employee->nin_birthlga,
                            ],
                            'residence_info' => [
                                'state' => $employee->nin_residence_state,
                                'town' => $employee->nin_residence_town,
                                'lga' => $employee->nin_residence_lga,
                                'address' => $employee->nin_residence_address,
                            ],
                            'photo' => $employee->nin_photo,
                            'report_id' => $employee->nin_report_id,
                        ];
                    }

                    return $data;
                }) : [],
                'pagination' => [
                    'current_page' => $employees->currentPage(),
                    'last_page' => $employees->lastPage(),
                    'per_page' => $employees->perPage(),
                    'total' => $employees->total(),
                    'from' => $employees->firstItem() ?? 0,
                    'to' => $employees->lastItem() ?? 0,
                ],
            ]);
        } catch (\Exception $e) {
            Log::error('Error fetching company employees: ' . $e->getMessage(), [
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);
            return response()->json([
                'success' => false,
                'message' => 'An error occurred while fetching employees.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Display the specified employee.
     */
    public function show(CompanyEmployee $companyEmployee): JsonResponse
    {
        try {
            // Check authorization
            if (!$this->isSystemAdmin()) {
                $user = request()->user();
                $companyId = $this->getCompanyIdForUser($user);

                if (!$companyId) {
                    return response()->json([
                        'success' => false,
                        'message' => 'Your account is not associated with a company. Please contact support.',
                    ], 403);
                }

                if ($companyEmployee->company_id !== $companyId) {
                    return response()->json([
                        'success' => false,
                        'message' => 'Unauthorized access to this employee.',
                    ], 403);
                }
            }

            $employeeData = [
                'id' => $companyEmployee->id,
                'first_name' => $companyEmployee->first_name,
                'last_name' => $companyEmployee->last_name,
                'full_name' => $companyEmployee->full_name,
                'email' => $companyEmployee->email,
                'phone' => $companyEmployee->phone,
                'employee_number' => $companyEmployee->employee_number,
                'department' => $companyEmployee->department,
                'position' => $companyEmployee->position,
                'hire_date' => $companyEmployee->hire_date?->toDateString(),
                'employment_status' => $companyEmployee->employment_status,
                'has_portal_access' => $companyEmployee->hasPortalAccess(),
                'has_submitted_nin' => $companyEmployee->hasSubmittedNin(),
                'is_nin_verified' => $companyEmployee->isNinVerified(),
                'is_validated' => $companyEmployee->is_validated ?? false,
                'nin_verified_at' => $companyEmployee->nin_verified_at?->toIso8601String(),
                'created_at' => $companyEmployee->created_at->toIso8601String(),
                'updated_at' => $companyEmployee->updated_at->toIso8601String(),
            ];

            // Include NIN data if verified
            if ($companyEmployee->isNinVerified()) {
                $employeeData['nin_data'] = [
                    'firstname' => $companyEmployee->nin_firstname,
                    'middlename' => $companyEmployee->nin_middlename,
                    'surname' => $companyEmployee->nin_surname,
                    'phone' => $companyEmployee->nin_phone,
                    'gender' => $companyEmployee->nin_gender,
                    'birthdate' => $companyEmployee->nin_birthdate?->format('Y-m-d'),
                    'birth_info' => [
                        'country' => $companyEmployee->nin_birthcountry,
                        'state' => $companyEmployee->nin_birthstate,
                        'lga' => $companyEmployee->nin_birthlga,
                    ],
                    'residence_info' => [
                        'state' => $companyEmployee->nin_residence_state,
                        'town' => $companyEmployee->nin_residence_town,
                        'lga' => $companyEmployee->nin_residence_lga,
                        'address' => $companyEmployee->nin_residence_address,
                    ],
                    'photo' => $companyEmployee->nin_photo,
                    'report_id' => $companyEmployee->nin_report_id,
                ];
            }

            return response()->json([
                'success' => true,
                'data' => $employeeData,
            ]);
        } catch (\Exception $e) {
            Log::error('Error fetching specific company employee: ' . $e->getMessage(), [
                'exception' => $e,
                'trace' => $e->getTraceAsString(),
            ]);
            return response()->json([
                'success' => false,
                'message' => 'An error occurred while fetching the employee.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }

    /**
     * Get company ID based on authenticated user type.
     */
    private function getCompanyId(CreateCompanyEmployeeRequest $request, $authenticatedUser): ?int
    {
        if ($this->isSystemAdmin()) {
            // System admin must provide company_id
            return $request->validated('company_id');
        }

        // Company admin - use their company_id
        // Use the authenticated user passed in (works with multi-guard auth)
        return $this->getCompanyIdForUser($authenticatedUser);
    }

    /**
     * Get company ID for a portal user, with fallback to find by email.
     */
    private function getCompanyIdForUser($user): ?int
    {
        if (!$user) {
            Log::error('No authenticated portal user found in getCompanyIdForUser');
            return null;
        }

        // If company_id is already set, return it
        if ($user->company_id) {
            return $user->company_id;
        }

        // Fallback: Try to find company by email match (for company_admin role)
        // This handles cases where company_id wasn't set during creation
        if ($user->role === 'company_admin') {
            $company = Company::where('email', $user->email)->first();

            if ($company) {
                // Auto-fix: Update the portal user's company_id
                $user->update(['company_id' => $company->id]);
                Log::info('Auto-fixed missing company_id for portal user', [
                    'user_id' => $user->id,
                    'user_email' => $user->email,
                    'company_id' => $company->id,
                ]);
                return $company->id;
            }
        }

        // Log for debugging if company_id is still null
        Log::warning('Portal user has no company_id and no matching company found', [
            'user_id' => $user->id,
            'user_email' => $user->email,
            'user_role' => $user->role,
            'company_id' => $user->company_id,
        ]);

        return null;
    }

    /**
     * Return the RSA public key for NIN encryption.
     * Requires authentication — NIN submission only happens post-login.
     */
    public function ninPublicKey(): JsonResponse
    {
        try {
            $publicKey = $this->ninEncryptionService->getPublicKey();

            return response()->json([
                'success'    => true,
                'public_key' => $publicKey,
            ]);
        } catch (\RuntimeException $e) {
            return response()->json([
                'success'      => false,
                'service_down' => true,
                'message'      => 'NIN encryption is not configured on this server.',
            ], 503);
        }
    }

    /**
     * Submit encrypted NIN for verification.
     */
    public function submitNin(SubmitNinRequest $request, CompanyEmployee $companyEmployee): JsonResponse
    {
        try {
            // Check authorization
            if (!$this->canManageEmployee($companyEmployee)) {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized access to this employee.',
                ], 403);
            }

            $validated = $request->validated();
            $encryptedNin = $validated['encrypted_nin'];
            $user = $request->user();

            // Log: NIN submission received
            $this->auditService->success(
                AuditLog::ACTION_NIN_SUBMITTED,
                AuditLog::ACTOR_PORTAL_USER,
                $user->id,
                $user->email,
                'CompanyEmployee', $companyEmployee->id,
                [], $request->ip(),
            );

            // Step 1: RSA-OAEP decrypt the NIN (frontend encrypted with server public key)
            try {
                $decryptedNin = $this->ninEncryptionService->decryptWithPrivateKey($encryptedNin);
            } catch (\Exception $e) {
                Log::error('NIN RSA decryption failed', [
                    'employee_id' => $companyEmployee->id,
                    'error' => $e->getMessage(),
                ]);
                return response()->json([
                    'success' => false,
                    'message' => 'Invalid encrypted data.',
                ], 422);
            }

            // Step 1b: Re-encrypt with AES-GCM for secure database storage
            try {
                $aesEncrypted = $this->ninEncryptionService->encrypt($decryptedNin);
            } catch (\Exception $e) {
                Log::error('NIN AES re-encryption failed', [
                    'employee_id' => $companyEmployee->id,
                    'error' => $e->getMessage(),
                ]);
                return response()->json([
                    'success' => false,
                    'message' => 'Failed to process NIN data.',
                ], 500);
            }

            // Step 2: Validate NIN format
            if (!$this->ninEncryptionService->validateNinFormat($decryptedNin)) {
                return response()->json([
                    'success' => false,
                    'message' => 'Invalid NIN format. NIN must be 11 digits.',
                ], 422);
            }

            // Step 3: Verify NIN with external API
            // Log: about to call external NIN API
            $this->auditService->success(
                AuditLog::ACTION_NIN_VERIFICATION_CALLED,
                AuditLog::ACTOR_SYSTEM,
                null, null,
                'CompanyEmployee', $companyEmployee->id,
                [], $request->ip(),
            );

            $verificationResult = $this->ninVerificationApiService->verifyNin($decryptedNin);

            if (!$verificationResult['success'] || !$verificationResult['verified']) {
                $this->auditService->failed(
                    AuditLog::ACTION_NIN_VERIFICATION_FAILED,
                    AuditLog::ACTOR_SYSTEM,
                    null, null,
                    'CompanyEmployee', $companyEmployee->id,
                    ['reason' => $verificationResult['message'] ?? 'NIN verification failed'],
                    $request->ip(),
                );

                $serviceDown = $verificationResult['service_unavailable'] ?? false;
                $status = $serviceDown ? 503 : 422;
                return response()->json(array_filter([
                    'success'      => false,
                    'service_down' => $serviceDown ?: null,
                    'message'      => $verificationResult['message'] ?? 'NIN verification failed.',
                ]), $status);
            }

            // Log: NIN verified successfully by external API
            $this->auditService->success(
                AuditLog::ACTION_NIN_VERIFICATION_SUCCESS,
                AuditLog::ACTOR_SYSTEM,
                null, null,
                'CompanyEmployee', $companyEmployee->id,
                ['report_id' => $verificationResult['report_id'] ?? null],
                $request->ip(),
            );

            // Step 4: Store encrypted NIN, verification data, and mark as verified
            $ninData = $verificationResult['data'] ?? [];

            // Step 5: Validate if employee data matches NIN data
            $isValidated = $this->validateEmployeeAgainstNin($companyEmployee, $ninData);

            // Log: data validation result
            $this->auditService->log(
                $isValidated ? AuditLog::ACTION_NIN_VALIDATED : AuditLog::ACTION_NIN_VALIDATION_FAILED,
                AuditLog::ACTOR_SYSTEM,
                null, null,
                $isValidated ? AuditLog::STATUS_SUCCESS : AuditLog::STATUS_FAILED,
                'CompanyEmployee', $companyEmployee->id,
                [], $request->ip(),
            );

            $companyEmployee->update([
                'nin_encrypted' => $aesEncrypted['iv'] . ':' . $aesEncrypted['ciphertext'] . ':' . $aesEncrypted['tag'],
                'is_nin_verified' => true,
                'is_validated' => $isValidated,
                'nin_verified_at' => now(),
                'nin_verification_token' => null,
                // Store NIN verification data from external API (Dojah field names)
                'nin_firstname' => $ninData['first_name'] ?? null,
                'nin_middlename' => $ninData['middle_name'] ?? null,
                'nin_surname' => $ninData['last_name'] ?? null,
                'nin_phone' => $ninData['phone_number'] ?? null,
                'nin_gender' => $ninData['gender'] ?? null,
                'nin_birthdate' => $ninData['date_of_birth'] ?? null,
                'nin_birthcountry' => $ninData['birthcountry'] ?? null,
                'nin_birthstate' => $ninData['birthstate'] ?? null,
                'nin_birthlga' => $ninData['birthlga'] ?? null,
                'nin_residence_state' => $ninData['residence_state'] ?? null,
                'nin_residence_town' => $ninData['residence_town'] ?? null,
                'nin_residence_lga' => $ninData['residence_lga'] ?? null,
                'nin_residence_address' => $ninData['residence_address'] ?? null,
                'nin_photo' => $ninData['photo'] ?? null,
                'nin_report_id' => $verificationResult['report_id'] ?? null,
            ]);

            // Refresh model to load newly saved values from database
            $companyEmployee->refresh();

            return response()->json([
                'success' => true,
                'message' => 'NIN verified and stored successfully.',
                'data' => [
                    'id' => $companyEmployee->id,
                    'first_name' => $companyEmployee->first_name,
                    'last_name' => $companyEmployee->last_name,
                    'email' => $companyEmployee->email,
                    'has_submitted_nin' => $companyEmployee->hasSubmittedNin(),
                    'is_nin_verified' => true,
                    'is_validated' => $companyEmployee->is_validated,
                    'nin_verified_at' => $companyEmployee->nin_verified_at?->toIso8601String(),
                    // NIN Verification Data from External API
                    'nin_data' => [
                        'firstname' => $companyEmployee->nin_firstname,
                        'middlename' => $companyEmployee->nin_middlename,
                        'surname' => $companyEmployee->nin_surname,
                        'phone' => $companyEmployee->nin_phone,
                        'gender' => $companyEmployee->nin_gender,
                        'birthdate' => $companyEmployee->nin_birthdate?->format('Y-m-d'),
                        'birth_info' => [
                            'country' => $companyEmployee->nin_birthcountry,
                            'state' => $companyEmployee->nin_birthstate,
                            'lga' => $companyEmployee->nin_birthlga,
                        ],
                        'residence_info' => [
                            'state' => $companyEmployee->nin_residence_state,
                            'town' => $companyEmployee->nin_residence_town,
                            'lga' => $companyEmployee->nin_residence_lga,
                            'address' => $companyEmployee->nin_residence_address,
                        ],
                        'photo' => $companyEmployee->nin_photo,
                        'report_id' => $companyEmployee->nin_report_id,
                    ],
                ],
            ]);
        } catch (\Exception $e) {
            Log::error('Error submitting NIN: ' . $e->getMessage(), [
                'exception' => $e,
                'employee_id' => $companyEmployee->id,
            ]);
            return response()->json([
                'success' => false,
                'message' => 'An error occurred while submitting NIN.',
                'error' => config('app.debug') ? $e->getMessage() : 'Internal server error',
            ], 500);
        }
    }


    /**
     * Check if authenticated user can manage this employee.
     */
    private function canManageEmployee(CompanyEmployee $employee): bool
    {
        if ($this->isSystemAdmin()) {
            return true;
        }

        $user = request()->user();
        $companyId = $this->getCompanyIdForUser($user);

        return $companyId && $employee->company_id === $companyId;
    }

    /**
     * Store beneficiaries for an employee.
     */
    public function storeBeneficiaries(
        StoreBeneficiariesRequest $request,
        CompanyEmployee $companyEmployee
    ): JsonResponse {
        try {
            // Authorization: Only the employee themselves can add beneficiaries
            $user = $request->user();

            if (!$user instanceof \App\Models\PortalUser) {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized. Only employees can add beneficiaries.',
                ], 403);
            }

            // Only employees can add beneficiaries
            if ($user->role !== 'employee') {
                return response()->json([
                    'success' => false,
                    'message' => 'Only employees can add beneficiaries.',
                ], 403);
            }

            if (!$user->employee_id || $user->employee_id !== $companyEmployee->id) {
                return response()->json([
                    'success' => false,
                    'message' => 'You can only add beneficiaries for yourself.',
                ], 403);
            }

            $validated = $request->validated();

            DB::beginTransaction();

            try {
                // Sync pattern: Update existing, create new, delete missing
                $submittedIds = [];
                $savedBeneficiaries = [];

                foreach ($validated['beneficiaries'] as $index => $beneficiaryData) {
                    $beneficiaryId = $beneficiaryData['id'] ?? null;

                    // Handle file uploads (only if new files provided)
                    $utilityBillPath = null;
                    $identificationPath = null;

                    if ($request->hasFile("beneficiaries.{$index}.utility_bill")) {
                        $utilityBillPath = $request->file("beneficiaries.{$index}.utility_bill")
                            ->store('beneficiaries/utility-bills', 'kyc');
                    }

                    if ($request->hasFile("beneficiaries.{$index}.identification_document")) {
                        $identificationPath = $request->file("beneficiaries.{$index}.identification_document")
                            ->store('beneficiaries/identifications', 'kyc');
                    }

                    if ($beneficiaryId) {
                        // UPDATE existing beneficiary
                        $beneficiary = Beneficiary::findOrFail($beneficiaryId);

                        // Verify ownership
                        if ($beneficiary->company_employee_id !== $companyEmployee->id) {
                            throw new \Exception('Cannot update beneficiary belonging to another employee.');
                        }

                        $updateData = [
                            'first_name' => $beneficiaryData['first_name'],
                            'last_name' => $beneficiaryData['last_name'],
                            'address' => $beneficiaryData['address'],
                            'date_of_birth' => $beneficiaryData['date_of_birth'],
                            'percentage_allocation' => $beneficiaryData['percentage_allocation'],
                        ];

                        // Only update file paths if new files were uploaded
                        if ($utilityBillPath) {
                            // Delete old file
                            if ($beneficiary->utility_bill_path) {
                                Storage::disk('kyc')->delete($beneficiary->utility_bill_path);
                            }
                            $updateData['utility_bill_path'] = $utilityBillPath;
                        }

                        if ($identificationPath) {
                            // Delete old file
                            if ($beneficiary->identification_path) {
                                Storage::disk('kyc')->delete($beneficiary->identification_path);
                            }
                            $updateData['identification_path'] = $identificationPath;
                        }

                        $beneficiary->update($updateData);
                        $submittedIds[] = $beneficiary->id;
                    } else {
                        // CREATE new beneficiary
                        $beneficiary = Beneficiary::create([
                            'company_employee_id' => $companyEmployee->id,
                            'first_name' => $beneficiaryData['first_name'],
                            'last_name' => $beneficiaryData['last_name'],
                            'address' => $beneficiaryData['address'],
                            'date_of_birth' => $beneficiaryData['date_of_birth'],
                            'percentage_allocation' => $beneficiaryData['percentage_allocation'],
                            'utility_bill_path' => $utilityBillPath,
                            'identification_path' => $identificationPath,
                        ]);
                        $submittedIds[] = $beneficiary->id;
                    }

                    $savedBeneficiaries[] = [
                        'id' => $beneficiary->id,
                        'first_name' => $beneficiary->first_name,
                        'last_name' => $beneficiary->last_name,
                        'address' => $beneficiary->address,
                        'date_of_birth' => $beneficiary->date_of_birth->format('Y-m-d'),
                        'percentage_allocation' => (float) $beneficiary->percentage_allocation,
                        'utility_bill_url' => $beneficiary->utility_bill_url,
                        'identification_url' => $beneficiary->identification_url,
                    ];
                }

                // DELETE beneficiaries that were not in the submitted list
                $deletedBeneficiaries = $companyEmployee->beneficiaries()
                    ->whereNotIn('id', $submittedIds)
                    ->get();

                foreach ($deletedBeneficiaries as $beneficiary) {
                    // Delete associated files
                    if ($beneficiary->utility_bill_path) {
                        Storage::disk('kyc')->delete($beneficiary->utility_bill_path);
                    }
                    if ($beneficiary->identification_path) {
                        Storage::disk('kyc')->delete($beneficiary->identification_path);
                    }
                    $beneficiary->delete();
                }

                DB::commit();

                $this->auditService->success(
                    AuditLog::ACTION_BENEFICIARIES_SUBMITTED,
                    AuditLog::ACTOR_PORTAL_USER,
                    $user->id,
                    $user->email,
                    'CompanyEmployee', $companyEmployee->id,
                    ['beneficiary_count' => count($savedBeneficiaries)],
                    $request->ip(),
                );

                return response()->json([
                    'success' => true,
                    'message' => 'Beneficiaries saved successfully.',
                    'data' => [
                        'count' => count($savedBeneficiaries),
                        'total_allocation' => array_sum(array_column($savedBeneficiaries, 'percentage_allocation')),
                        'beneficiaries' => $savedBeneficiaries,
                    ],
                ], 201);

            } catch (\Exception $e) {
                DB::rollBack();
                throw $e;
            }

        } catch (\Exception $e) {
            Log::error('Error saving beneficiaries: ' . $e->getMessage(), [
                'employee_id' => $companyEmployee->id,
                'trace' => $e->getTraceAsString(),
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while saving beneficiaries.',
                'error' => $e->getMessage(),
            ], 500);
        }
    }

    /**
     * Get beneficiaries for an employee.
     */
    public function getBeneficiaries(CompanyEmployee $companyEmployee): JsonResponse
    {
        try {
            // Authorization: Employee can view their own, company admin can view their company's employees
            $user = request()->user();

            if ($user instanceof \App\Models\PortalUser) {
                // If employee, must be their own record
                if ($user->role === 'employee' && $user->employee_id !== $companyEmployee->id) {
                    return response()->json([
                        'success' => false,
                        'message' => 'You can only view your own beneficiaries.',
                    ], 403);
                }

                // If company admin, must be from their company
                if ($user->role === 'company_admin' && $user->company_id !== $companyEmployee->company_id) {
                    return response()->json([
                        'success' => false,
                        'message' => 'You can only view beneficiaries for employees in your company.',
                    ], 403);
                }
            }
            // System admins can view all

            $beneficiaries = $companyEmployee->beneficiaries()->get()->map(function ($beneficiary) {
                return [
                    'id' => $beneficiary->id,
                    'first_name' => $beneficiary->first_name,
                    'last_name' => $beneficiary->last_name,
                    'full_name' => $beneficiary->full_name,
                    'address' => $beneficiary->address,
                    'date_of_birth' => $beneficiary->date_of_birth->format('Y-m-d'),
                    'percentage_allocation' => (float) $beneficiary->percentage_allocation,
                    'utility_bill_url' => $beneficiary->utility_bill_url,
                    'identification_url' => $beneficiary->identification_url,
                    'created_at' => $beneficiary->created_at->toIso8601String(),
                ];
            });

            return response()->json([
                'success' => true,
                'data' => [
                    'employee' => [
                        'id' => $companyEmployee->id,
                        'name' => $companyEmployee->full_name,
                    ],
                    'count' => $beneficiaries->count(),
                    'total_allocation' => $beneficiaries->sum('percentage_allocation'),
                    'beneficiaries' => $beneficiaries,
                ],
            ]);

        } catch (\Exception $e) {
            Log::error('Error retrieving beneficiaries: ' . $e->getMessage(), [
                'employee_id' => $companyEmployee->id,
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while retrieving beneficiaries.',
            ], 500);
        }
    }

    /**
     * Check if the authenticated user is a system admin.
     */
    private function isSystemAdmin(): bool
    {
        // When using multi-guard auth (sanctum,portal_api), check the user type
        $user = request()->user();

        // System admin is User model, portal users are PortalUser model
        return $user instanceof \App\Models\User;
    }

    /**
     * Validate if employee data matches NIN data.
     * Checks first_name, last_name, and date_of_birth for exact match.
     */
    private function validateEmployeeAgainstNin(CompanyEmployee $employee, array $ninData): bool
    {
        // Extract NIN data (Dojah field names)
        $ninFirstName = $ninData['first_name'] ?? null;
        $ninSurname = $ninData['last_name'] ?? null;
        $ninBirthdate = $ninData['date_of_birth'] ?? null;

        // If any required field is missing from NIN data, validation fails
        if (!$ninFirstName || !$ninSurname || !$ninBirthdate) {
            return false;
        }

        // Convert names to lowercase for case-insensitive comparison
        $employeeFirstName = strtolower(trim($employee->first_name));
        $employeeLastName = strtolower(trim($employee->last_name));
        $ninFirstNameLower = strtolower(trim($ninFirstName));
        $ninSurnameLower = strtolower(trim($ninSurname));

        // Check if first names match
        $firstNameMatches = $employeeFirstName === $ninFirstNameLower;

        // Check if last names match
        $lastNameMatches = $employeeLastName === $ninSurnameLower;

        // Check if dates of birth match
        $dateOfBirthMatches = false;
        if ($employee->date_of_birth) {
            // Convert NIN birthdate string to Carbon date for comparison
            try {
                $ninBirthdateCarbon = \Carbon\Carbon::parse($ninBirthdate);
                $dateOfBirthMatches = $employee->date_of_birth->isSameDay($ninBirthdateCarbon);
            } catch (\Exception $e) {
                Log::warning('Failed to parse NIN birthdate for validation', [
                    'nin_birthdate' => $ninBirthdate,
                    'error' => $e->getMessage(),
                ]);
                $dateOfBirthMatches = false;
            }
        }

        // Log validation result for debugging
        Log::info('NIN validation check', [
            'employee_id' => $employee->id,
            'first_name_matches' => $firstNameMatches,
            'last_name_matches' => $lastNameMatches,
            'date_of_birth_matches' => $dateOfBirthMatches,
            'overall_validated' => $firstNameMatches && $lastNameMatches && $dateOfBirthMatches,
        ]);

        // All three must match for validation to pass
        return $firstNameMatches && $lastNameMatches && $dateOfBirthMatches;
    }

    /**
     * Export employees to CSV.
     */
    public function exportCsv(Request $request)
    {
        try {
            $user = $request->user();

            // Get query parameters
            $companyId = $request->input('company_id');
            $filters = [
                'search' => $request->input('search'),
                'employment_status' => $request->input('employment_status'),
                'nin_verified' => $request->input('nin_verified'),
            ];

            // Authorization and data retrieval
            if ($this->isSystemAdmin()) {
                // System admin can export any company's employees
                if (!$companyId) {
                    return response()->json([
                        'success' => false,
                        'message' => 'System admins must specify company_id for export.',
                    ], 422);
                }

                // Verify company exists
                $company = Company::find($companyId);
                if (!$company) {
                    return response()->json([
                        'success' => false,
                        'message' => 'Company not found.',
                    ], 404);
                }

                $employees = $this->companyEmployeeService->getEmployeesByCompany($companyId, 10000, $filters);
            } elseif ($user instanceof \App\Models\PortalUser && $user->role === 'company_admin') {
                // Company admin can only export their own employees
                $companyId = $user->company_id;
                $company = $user->company;
                $employees = $this->companyEmployeeService->getEmployeesByCompany($companyId, 10000, $filters);
            } else {
                return response()->json([
                    'success' => false,
                    'message' => 'Unauthorized to export employees.',
                ], 403);
            }

            // Load beneficiaries for all employees
            $employees->load('beneficiaries');

            // Generate CSV
            $csv = $this->generateEmployeeCsv($employees, $company);

            // Return CSV as download
            $filename = 'employees_' . preg_replace('/[^a-zA-Z0-9_-]/', '_', $company->name) . '_' . now()->format('Y-m-d_His') . '.csv';

            $this->auditService->success(
                AuditLog::ACTION_EMPLOYEE_CSV_EXPORTED,
                $this->isSystemAdmin() ? AuditLog::ACTOR_ADMIN : AuditLog::ACTOR_PORTAL_USER,
                $user->id,
                $user->email,
                'Company', $companyId,
                ['company_name' => $company->name, 'record_count' => $employees->count(), 'filename' => $filename],
                $request->ip(),
            );

            // Add UTF-8 BOM for Excel compatibility
            $csvWithBom = "\xEF\xBB\xBF" . $csv;

            return response($csvWithBom, 200, [
                'Content-Type' => 'text/csv; charset=UTF-8',
                'Content-Disposition' => 'attachment; filename="' . $filename . '"',
                'Cache-Control' => 'must-revalidate, post-check=0, pre-check=0',
                'Pragma' => 'public',
            ]);

        } catch (\Exception $e) {
            Log::error('Error exporting employees: ' . $e->getMessage(), [
                'user_id' => $request->user()?->id,
                'company_id' => $companyId ?? null,
            ]);

            return response()->json([
                'success' => false,
                'message' => 'An error occurred while exporting employees.',
            ], 500);
        }
    }

    /**
     * Generate CSV content from employees data.
     */
    private function generateEmployeeCsv($employees, $company): string
    {
        $output = fopen('php://temp', 'r+');

        // CSV Headers
        $headers = [
            'Employee ID',
            'First Name',
            'Last Name',
            'Email',
            'Date of Birth',
            'Phone',
            'Employee Number',
            'Department',
            'Position',
            'Hire Date',
            'Employment Status',
            'Has Portal Access',
            'Has Submitted NIN',
            'Is NIN Verified',
            'Is Validated',
            'NIN Verified At',
            // Beneficiary columns (up to 5)
            'Beneficiary 1 Name',
            'Beneficiary 1 Address',
            'Beneficiary 1 DOB',
            'Beneficiary 1 Allocation %',
            'Beneficiary 2 Name',
            'Beneficiary 2 Address',
            'Beneficiary 2 DOB',
            'Beneficiary 2 Allocation %',
            'Beneficiary 3 Name',
            'Beneficiary 3 Address',
            'Beneficiary 3 DOB',
            'Beneficiary 3 Allocation %',
            'Beneficiary 4 Name',
            'Beneficiary 4 Address',
            'Beneficiary 4 DOB',
            'Beneficiary 4 Allocation %',
            'Beneficiary 5 Name',
            'Beneficiary 5 Address',
            'Beneficiary 5 DOB',
            'Beneficiary 5 Allocation %',
        ];

        fputcsv($output, $headers);

        // Data rows
        foreach ($employees as $employee) {
            $row = [
                $employee->id,
                $employee->first_name,
                $employee->last_name,
                $employee->email,
                $employee->date_of_birth?->format('Y-m-d') ?? '',
                $employee->phone ?? '',
                $employee->employee_number ?? '',
                $employee->department ?? '',
                $employee->position ?? '',
                $employee->hire_date?->format('Y-m-d') ?? '',
                $employee->employment_status,
                $employee->hasPortalAccess() ? 'Yes' : 'No',
                $employee->hasSubmittedNin() ? 'Yes' : 'No',
                $employee->isNinVerified() ? 'Yes' : 'No',
                $employee->is_validated ? 'Yes' : 'No',
                $employee->nin_verified_at?->format('Y-m-d H:i:s') ?? '',
            ];

            // Add beneficiary data (up to 5)
            $beneficiaries = $employee->beneficiaries->take(5);
            for ($i = 0; $i < 5; $i++) {
                if (isset($beneficiaries[$i])) {
                    $beneficiary = $beneficiaries[$i];
                    $row[] = $beneficiary->full_name;
                    $row[] = $beneficiary->address;
                    $row[] = $beneficiary->date_of_birth?->format('Y-m-d') ?? '';
                    $row[] = $beneficiary->percentage_allocation;
                } else {
                    // Empty cells if beneficiary doesn't exist
                    $row[] = '';
                    $row[] = '';
                    $row[] = '';
                    $row[] = '';
                }
            }

            fputcsv($output, $row);
        }

        rewind($output);
        $csv = stream_get_contents($output);
        fclose($output);

        return $csv;
    }
}
