<?php

namespace App\Http\Controllers\Traits;

use App\Models\InductionDocument;
use App\Models\InductionDocumentSignature;
use App\Models\EmpCompanyDetails;
use App\Models\LinkManagement;
use App\Models\User;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Facades\Validator;

trait InductionTrait
{
    /**
     * Get employees/users based on role types
     * 
     * @param array $roleTypes - ['internal', 'external', 'subcontractor', 'all']
     * @param int $customerId
     * @param int $workspaceId
     * @return array
     */
    protected function getUsersByRoleTypes($roleTypes, $customerId, $workspaceId)
    {
        $users = [];
        
        // If 'all' is in role types, get everyone
        if (in_array('all', $roleTypes)) {
            // Get internal employees (user_type = 0)
            $internalEmployees = EmpCompanyDetails::withoutGlobalScope(\App\Scopes\NotDeletedScope::class)
                ->where('customer_id', $customerId)
                ->where('workspace_id', $workspaceId)
                ->where('user_type', 0)
                ->where('del', '0')
                ->with('empPersonalDetails')
                ->get();
            
            // Get external employees (user_type = 1)
            $externalEmployees = EmpCompanyDetails::withoutGlobalScope(\App\Scopes\NotDeletedScope::class)
                ->where('customer_id', $customerId)
                ->where('workspace_id', $workspaceId)
                ->where('user_type', 1)
                ->where('del', '0')
                ->with('empPersonalDetails')
                ->get();
            
            // Get subcontractors
            $subcontractors = LinkManagement::where('customer_id', $customerId)
                ->where('workspace_id', $workspaceId)
                ->get();
            
            foreach ($internalEmployees as $emp) {
                $firstName = $emp->empPersonalDetails->first_name ?? '';
                $lastName = $emp->empPersonalDetails->last_name ?? '';
                $fullName = trim($firstName . ' ' . $lastName);
                
                $users[] = [
                    'id' => $emp->id,
                    'name' => $fullName ?: 'Unknown',
                    'type' => 'employee',
                    'access_role' => $emp->access_role ?? null, // Include access_role for role lookup
                    'role_type' => 'internal',
                    'email' => $emp->employee_email ?? '',
                ];
            }
            
            foreach ($externalEmployees as $emp) {
                $firstName = $emp->empPersonalDetails->first_name ?? '';
                $lastName = $emp->empPersonalDetails->last_name ?? '';
                $fullName = trim($firstName . ' ' . $lastName);
                
                $users[] = [
                    'id' => $emp->id,
                    'name' => $fullName ?: 'Unknown',
                    'type' => 'employee',
                    'access_role' => $emp->access_role ?? null, // Include access_role for role lookup
                    'role_type' => 'external',
                    'email' => $emp->employee_email ?? '',
                ];
            }
            
            foreach ($subcontractors as $sub) {
                $users[] = [
                    'id' => $sub->id,
                    'name' => $sub->name ?? '',
                    'type' => 'subcontractor',
                    'role_type' => 'subcontractor',
                    'email' => $sub->email ?? '',
                ];
            }
        } else {
            // Get specific role types
            if (in_array('internal', $roleTypes)) {
                $internalEmployees = EmpCompanyDetails::withoutGlobalScope(\App\Scopes\NotDeletedScope::class)
                    ->where('customer_id', $customerId)
                    ->where('workspace_id', $workspaceId)
                    ->where('user_type', 0)
                    ->where('del', '0')
                    ->with('empPersonalDetails')
                    ->get();
                
                foreach ($internalEmployees as $emp) {
                    $firstName = $emp->empPersonalDetails->first_name ?? '';
                    $lastName = $emp->empPersonalDetails->last_name ?? '';
                    $fullName = trim($firstName . ' ' . $lastName);
                    
                    $users[] = [
                        'id' => $emp->id,
                        'name' => $fullName ?: 'Unknown',
                        'type' => 'employee',
                        'access_role' => $emp->access_role ?? null, // Include access_role for role lookup
                        'role_type' => 'internal',
                        'email' => $emp->employee_email ?? '',
                    ];
                }
            }
            
            if (in_array('external', $roleTypes)) {
                $externalEmployees = EmpCompanyDetails::withoutGlobalScope(\App\Scopes\NotDeletedScope::class)
                    ->where('customer_id', $customerId)
                    ->where('workspace_id', $workspaceId)
                    ->where('user_type', 1)
                    ->where('del', '0')
                    ->with('empPersonalDetails')
                    ->get();
                
                foreach ($externalEmployees as $emp) {
                    $firstName = $emp->empPersonalDetails->first_name ?? '';
                    $lastName = $emp->empPersonalDetails->last_name ?? '';
                    $fullName = trim($firstName . ' ' . $lastName);
                    
                    $users[] = [
                        'id' => $emp->id,
                        'name' => $fullName ?: 'Unknown',
                        'type' => 'employee',
                        'access_role' => $emp->access_role ?? null, // Include access_role for role lookup
                        'role_type' => 'external',
                        'email' => $emp->employee_email ?? '',
                    ];
                }
            }
            
            if (in_array('subcontractor', $roleTypes)) {
                $subcontractors = LinkManagement::where('customer_id', $customerId)
                    ->where('workspace_id', $workspaceId)
                    ->get();
                
                foreach ($subcontractors as $sub) {
                    $users[] = [
                        'id' => $sub->id,
                        'name' => $sub->name ?? '',
                        'type' => 'subcontractor',
                        'role_type' => 'subcontractor',
                        'email' => $sub->email ?? '',
                    ];
                }
            }
        }
        
        return $users;
    }

    /**
     * Get next version number based on parent_document_id chain
     */
    protected function getNextVersion($parentDocumentId, $customerId, $workspaceId = null)
    {
        // Find the root document (the one with parent_document_id = null)
        $rootDocumentId = $parentDocumentId;
        $query = InductionDocument::where('id', $parentDocumentId)
            ->where('customer_id', $customerId)
            ->where('del', '0');
        if ($workspaceId) {
            $query->where('workspace_id', $workspaceId);
        }
        $currentDoc = $query->first();
        
        if (!$currentDoc) {
            return 'v1';
        }
        
        // Traverse up to find the root document
        while ($currentDoc && $currentDoc->parent_document_id) {
            $rootDocumentId = $currentDoc->parent_document_id;
            $query = InductionDocument::where('id', $rootDocumentId)
                ->where('customer_id', $customerId)
                ->where('del', '0');
            if ($workspaceId) {
                $query->where('workspace_id', $workspaceId);
            }
            $currentDoc = $query->first();
        }
        
        // Get all versions in the chain (root and all children)
        $query = InductionDocument::where(function($q) use ($rootDocumentId) {
            $q->where('id', $rootDocumentId)
              ->orWhere('parent_document_id', $rootDocumentId);
        })
        ->where('customer_id', $customerId)
        ->where('del', '0');
        
        if ($workspaceId) {
            $query->where('workspace_id', $workspaceId);
        }
        
        // Get all versions and sort by numeric value, not string
        $allVersions = $query->get();
        
        if ($allVersions->isEmpty()) {
            return 'v1';
        }
        
        // Extract numeric version numbers and find the maximum
        $maxVersion = 0;
        foreach ($allVersions as $doc) {
            $versionNumber = (int) str_replace('v', '', $doc->version);
            if ($versionNumber > $maxVersion) {
                $maxVersion = $versionNumber;
            }
        }
        
        // Increment and return next version
        return 'v' . ($maxVersion + 1);
    }

    /**
     * Upload PDF file for induction document
     */
    protected function uploadInductionDocument($file, $directory = 'InductionDocuments')
    {
        if (!$file || !$file->isValid()) {
            return null;
        }

        // Validate file type (PDF only, max 10MB)
        $validator = Validator::make(['file' => $file], [
            'file' => 'required|mimes:pdf|max:10240', // 10MB = 10240 KB
        ]);

        if ($validator->fails()) {
            return ['error' => $validator->errors()->first()];
        }

        // Create directory if it doesn't exist
        $uploadPath = public_path($directory);
        if (!File::exists($uploadPath)) {
            File::makeDirectory($uploadPath, 0755, true);
        }

        // Generate unique filename
        $extension = $file->getClientOriginalExtension();
        $originalName = pathinfo($file->getClientOriginalName(), PATHINFO_FILENAME);
        $sanitizedFileName = preg_replace('/[^a-zA-Z0-9_-]/', '', $originalName);
        $sanitizedFileName = substr($sanitizedFileName, 0, 100);
        $uniqueFileName = time() . '_' . $sanitizedFileName . '.' . $extension;

        // Get file size BEFORE moving (once moved, the file object loses access)
        $fileSize = $file->getSize();
        $originalFileName = $file->getClientOriginalName();

        // Move file
        $file->move($uploadPath, $uniqueFileName);

        return [
            'path' => "$directory/$uniqueFileName",
            'name' => $originalFileName,
            'size' => $fileSize,
        ];
    }

    /**
     * Get signature statistics for a document version
     */
    protected function getSignatureStatistics($documentId, $version, $roleTypes, $customerId, $workspaceId)
    {
        // Get all users who should sign based on role types
        $requiredUsers = $this->getUsersByRoleTypes($roleTypes, $customerId, $workspaceId);
        $totalRequired = count($requiredUsers);

        // Get signed users for this version
        $signedSignatures = InductionDocumentSignature::where('induction_document_id', $documentId)
            ->where('document_version', $version)
            ->where('is_valid', true)
            ->where('del', '0')
            ->get();

        $signedCount = 0;
        $signedUserIds = [];

        foreach ($signedSignatures as $signature) {
            if ($signature->employee_id) {
                $signedUserIds[] = ['type' => 'employee', 'id' => $signature->employee_id];
            } elseif ($signature->user_id) {
                $signedUserIds[] = ['type' => 'user', 'id' => $signature->user_id];
            }
            $signedCount++;
        }

        // Get not signed users
        $notSignedUsers = [];
        foreach ($requiredUsers as $user) {
            $isSigned = false;
            foreach ($signedUserIds as $signed) {
                if ($user['type'] === 'employee' && $signed['type'] === 'employee' && $user['id'] == $signed['id']) {
                    $isSigned = true;
                    break;
                } elseif ($user['type'] === 'subcontractor' && $signed['type'] === 'user' && $user['id'] == $signed['id']) {
                    $isSigned = true;
                    break;
                }
            }
            if (!$isSigned) {
                $notSignedUsers[] = $user;
            }
        }

        return [
            'total_required' => $totalRequired,
            'signed_count' => $signedCount,
            'not_signed_count' => count($notSignedUsers),
            'signed_users' => $signedSignatures->map(function($sig) {
                $data = [
                    'id' => $sig->id,
                    'signed_at' => $sig->signed_at,
                    'signature_path' => $sig->signature_path,
                ];
                
                if ($sig->employee_id) {
                    $emp = EmpCompanyDetails::withoutGlobalScope(\App\Scopes\NotDeletedScope::class)
                        ->with('empPersonalDetails')
                        ->find($sig->employee_id);
                    if ($emp) {
                        $firstName = $emp->empPersonalDetails->first_name ?? '';
                        $lastName = $emp->empPersonalDetails->last_name ?? '';
                        $fullName = trim($firstName . ' ' . $lastName);
                        
                        $data['name'] = $fullName ?: 'Unknown';
                        $data['type'] = 'employee';
                        $data['employee_id'] = $sig->employee_id; // Include employee_id for role lookup
                        $data['access_role'] = $emp->access_role; // Include access_role code
                        $data['role_type'] = $emp->user_type == 0 ? 'internal' : 'external';
                        $data['email'] = $emp->employee_email ?? '';
                    } else {
                        $data['name'] = 'Unknown';
                        $data['type'] = 'employee';
                        $data['employee_id'] = $sig->employee_id;
                        $data['email'] = '';
                    }
                } elseif ($sig->user_id) {
                    $user = User::find($sig->user_id);
                    if ($user) {
                        $data['name'] = $user->name ?? 'Unknown';
                        $data['type'] = 'user';
                        $data['email'] = $user->email ?? '';
                    } else {
                        $data['name'] = 'Unknown';
                        $data['type'] = 'user';
                        $data['email'] = '';
                    }
                }
                
                return $data;
            }),
            'not_signed_users' => $notSignedUsers,
        ];
    }

    /**
     * Invalidate signatures for major update
     */
    protected function invalidateDocumentSignatures($documentId, $version = null)
    {
        $query = InductionDocumentSignature::where('induction_document_id', $documentId)
            ->where('is_valid', true);
        
        if ($version) {
            $query->where('document_version', $version);
        }
        
        return $query->update(['is_valid' => false]);
    }

    /**
     * Get the latest version of a document chain
     * 
     * @param int $documentId The document ID (can be any version in the chain)
     * @param int $customerId
     * @param int|null $workspaceId
     * @return InductionDocument|null Returns the latest version document or null
     */
    protected function getLatestVersion($documentId, $customerId, $workspaceId = null)
    {
        // Find the root document (the one with parent_document_id = null)
        $rootDocumentId = $documentId;
        $currentDoc = InductionDocument::where('id', $documentId)
            ->where('customer_id', $customerId)
            ->where('del', '0')
            ->first();
        
        if (!$currentDoc) {
            return null;
        }
        
        // Traverse up to find the root document
        while ($currentDoc && $currentDoc->parent_document_id) {
            $rootDocumentId = $currentDoc->parent_document_id;
            $currentDoc = InductionDocument::where('id', $rootDocumentId)
                ->where('customer_id', $customerId)
                ->where('del', '0')
                ->first();
            
            if (!$currentDoc) {
                break;
            }
        }
        
        // Get all versions in the chain (root and all children)
        $query = InductionDocument::where(function($q) use ($rootDocumentId) {
            $q->where('id', $rootDocumentId)
              ->orWhere('parent_document_id', $rootDocumentId);
        })
        ->where('customer_id', $customerId)
        ->where('del', '0');
        
        if ($workspaceId) {
            $query->where('workspace_id', $workspaceId);
        }
        
        // Get all versions and find the latest by version number
        $allVersions = $query->get();
        
        if ($allVersions->isEmpty()) {
            return null;
        }
        
        // Extract numeric version numbers and find the maximum
        $latestDoc = null;
        $maxVersion = 0;
        foreach ($allVersions as $doc) {
            $versionNumber = (int) str_replace('v', '', $doc->version);
            if ($versionNumber > $maxVersion) {
                $maxVersion = $versionNumber;
                $latestDoc = $doc;
            }
        }
        
        return $latestDoc;
    }

    /**
     * Get the previous version of a document (one version lower)
     * 
     * @param int $documentId The document ID
     * @param int $customerId
     * @param int|null $workspaceId
     * @return InductionDocument|null Returns the previous version document or null
     */
    protected function getPreviousVersion($documentId, $customerId, $workspaceId = null)
    {
        $currentDoc = InductionDocument::where('id', $documentId)
            ->where('customer_id', $customerId)
            ->where('del', '0')
            ->first();
        
        if (!$currentDoc) {
            return null;
        }
        
        // Get current version number
        $currentVersionNumber = (int) str_replace('v', '', $currentDoc->version);
        
        if ($currentVersionNumber <= 1) {
            return null; // No previous version
        }
        
        // Find the root document
        $rootDocumentId = $currentDoc->id;
        $tempDoc = $currentDoc;
        
        while ($tempDoc && $tempDoc->parent_document_id) {
            $rootDocumentId = $tempDoc->parent_document_id;
            $tempDoc = InductionDocument::where('id', $rootDocumentId)
                ->where('customer_id', $customerId)
                ->where('del', '0')
                ->first();
            
            if (!$tempDoc) {
                break;
            }
        }
        
        // Get all versions in the chain
        $query = InductionDocument::where(function($q) use ($rootDocumentId) {
            $q->where('id', $rootDocumentId)
              ->orWhere('parent_document_id', $rootDocumentId);
        })
        ->where('customer_id', $customerId)
        ->where('del', '0');
        
        if ($workspaceId) {
            $query->where('workspace_id', $workspaceId);
        }
        
        $allVersions = $query->get();
        
        // Find the version with version number = currentVersionNumber - 1
        $previousVersionNumber = $currentVersionNumber - 1;
        foreach ($allVersions as $doc) {
            $versionNumber = (int) str_replace('v', '', $doc->version);
            if ($versionNumber === $previousVersionNumber) {
                return $doc;
            }
        }
        
        return null;
    }
}

