<?php

namespace App\Http\Controllers\Traits;

use App\Models\EmpCompanyDetails;
use App\Models\EmpTeam;
use App\Models\Tier;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\File;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;




trait HelperTrait
{

    public function getLatestData($model, Request $request, $relations = [])
    {
        $latestData = $model->latest();
        if (!empty($relations)) {
            $relations = is_array($relations) ? $relations : [$relations];
            foreach ($relations as $relation) {
                $latestData = $latestData->with($relation);
            }
        }
        return $this->withCount($latestData);
    }

    public function handleFileImageUpload(Request $request, $directory = null, $currentFiles = null)
    {
        $directory = $directory ?? 'uploads'; // Default directory for uploads
        $uploadedPaths = [];
        $files = $request->allFiles(); // Get all uploaded files from the request
        foreach ($files as $key => $file) {
            if (!$file instanceof \Illuminate\Http\UploadedFile && !is_array($file)) {
                continue; // Skip non-file inputs
            }
            $fileItems = is_array($file) ? $file : [$file];
            foreach ($fileItems as $fileItem) {
                if (!$fileItem instanceof \Illuminate\Http\UploadedFile || !$fileItem->isValid()) {
                    continue;
                }
                // Get file extension and sanitize filename
                $extension = strtolower($fileItem->getClientOriginalExtension());
                $originalName = pathinfo($fileItem->getClientOriginalName(), PATHINFO_FILENAME);
                $sanitizedFileName = preg_replace('/[^a-zA-Z0-9_-]/', '', $originalName);
                $sanitizedFileName = substr($sanitizedFileName, 0, 100); // Limit filename length
                $uniqueFileName = time() . '_' . $sanitizedFileName . '.' . $extension;
                // Validate file type
                $allowedImageExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp'];
                $allowedDocumentExtensions = ['pdf', 'csv', 'doc', 'docx', 'xlsx', 'txt'];
                if (!in_array($extension, array_merge($allowedImageExtensions, $allowedDocumentExtensions))) {
                    continue; // Skip invalid file types
                }
                // Move file to public directory
                $fileItem->move(public_path($directory), $uniqueFileName);
                $uploadedPaths[] = [
                    'key' => $key, // Dynamic key
                    'path' => "$directory/$uniqueFileName",
                    'type' => in_array($extension, $allowedImageExtensions) ? 'image' : 'document'
                ];
                // Delete old file if it exists
                if (is_string($currentFiles) && File::exists(public_path($currentFiles))) {
                    File::delete(public_path($currentFiles));
                }
                if (is_array($currentFiles) && isset($currentFiles[$key])) {
                    foreach ((array) $currentFiles[$key] as $oldFilePath) {
                        if (File::exists(public_path($oldFilePath))) {
                            File::delete(public_path($oldFilePath));
                        }
                    }
                }
            }
        }
        return count($uploadedPaths) === 1 ? $uploadedPaths[0] : $uploadedPaths;
    }

    function createSlug($title)
    {
        return strtolower(preg_replace('/[^A-Za-z0-9-]+/', '-', trim($title)));
    }

    function generateTicketId()
    {
        do {
            $ticketId = 'TK-' . strtoupper(substr(uniqid(), -6));
        } while (\App\Models\HelpdeskTicket::where('ticket_id', $ticketId)->exists());
        return $ticketId;
    }

    function generateCsvFromQuery($query)
    {
        if ($query->getModel() === null) {
            return $this->message('Invalid query. Ensure the query is a valid Eloquent query.');
        }
        $modelName = strtolower(class_basename($query->getModel()));
        $directory = 'csv';
        $directoryPath = public_path($directory);
        if (!File::exists($directoryPath)) {
            File::makeDirectory($directoryPath, 0755, true);
        }
        $fileName = "{$modelName}.csv";
        $filePath = "{$directory}/{$fileName}";
        $fullFilePath = public_path($filePath);
        if (File::exists($fullFilePath)) {
            File::delete($fullFilePath);
        }
        $file = fopen($fullFilePath, 'w');
        $records = $query->get();
        if ($records->isEmpty()) {
            fclose($file);
            return $this->message('The query returned no records to export.');
        }
        $headers = array_keys($records->first()->toArray());
        fputcsv($file, $headers);
        foreach ($records as $record) {
            $flattenedRecord = array_map(function ($value) {
                if (is_array($value) || is_object($value)) {
                    return json_encode($value); // Convert to JSON string
                }
                return $value;
            }, $record->toArray());
            fputcsv($file, $flattenedRecord);
        }
        fclose($file);
        return asset($filePath);
    }

    function generateOrderId()
    {
        do {

            $OrderId = 'ODR-' . strtoupper(substr(uniqid(), -6));
        } while (\App\Models\Order::where('order_id', $OrderId)->exists());
        return $OrderId;
    }

    public static function generateCode($prefix = null)
    {
        $code = Str::upper(Str::random(10));
        if ($prefix) {
            return $prefix . $code;
        }
        return $code;
    }

    function getUserTable($user = null)
    {
        if (!$user) {
            $user = Auth::user();
        }
        if ($user instanceof \App\Models\User) {
            return 'customer';
        }
        if ($user instanceof \App\Models\EmpCompanyDetails) {
            return 'emp';
        }
        return null; // Return null if the user does not match either table
    }

    protected function getCustomerAndWorkspaceIds()
    {
        $userTable = $this->getUserTable();
        if ($userTable === 'customer') {
            return [
                'customer_id' => Auth::id(),
                'workspace_id' => Auth::user()->current_workspace_id,
                'flag' => 'customer',
            ];
        } elseif ($userTable === 'emp') {
            return [
                'customer_id' => Auth::user()->customer_id,
                'workspace_id' => Auth::user()->workspace_id,
                'flag' => 'emp',
            ];
        }
        return null;
    }

    protected function applyCustomerWorkspaceFilter($query)
    {
        $ids = $this->getCustomerAndWorkspaceIds();
        if (!$ids) {
            return $query->whereRaw('1 = 0'); // No results
        }
        return $query->where('customer_id', $ids['customer_id'])
            ->where('workspace_id', $ids['workspace_id']);
    }

    private function getPaymentStatusConfig($paymentStatus)
    {
        $configs = [
            // Pending - 0
            config('constants.payment_statuses.pending') => [
                'subject' => 'New Pending Payment Request',
                'status_text' => 'Pending',
                'color' => '#F59E0B', // Amber
                'background' => 'linear-gradient(135deg, #fff 0%, #fff 100%)',
                'icon' => '⏳',
                'message' => 'A new payment request requires your attention and approval.',
                'action_required' => true,
                'action_message' => 'Please verify the payment and approve this request through the admin dashboard'
            ],
            // Completed - 1
            config('constants.payment_statuses.completed') => [
                'subject' => 'Payment Successfully Processed',
                'status_text' => 'Completed',
                'color' => '#22C55E', // Green
                'background' => 'linear-gradient(135deg, #fff 0%, #fff 100%)',
                'icon' => '✅',
                'message' => 'A payment has been successfully processed and confirmed.',
                'action_required' => false,
                'action_message' => ''
            ],
            // Failed - 2
            config('constants.payment_statuses.failed') => [
                'subject' => 'Payment Failed',
                'status_text' => 'Failed',
                'color' => '#EF4444', // Red
                'background' => 'linear-gradient(135deg, #fff 0%, #fff 100%)',
                'icon' => '❌',
                'message' => 'A payment attempt has failed and requires attention.',
                'action_required' => true,
                'action_message' => 'Please review the payment details and contact the customer if necessary'
            ],
            // Refunded - 3
            config('constants.payment_statuses.refunded') => [
                'subject' => 'Payment Refunded',
                'status_text' => 'Refunded',
                'color' => '#6366F1', // Indigo
                'background' => 'linear-gradient(135deg, #fff 0%, #fff 100%)',
                'icon' => '↩️',
                'message' => 'A payment has been refunded to the customer.',
                'action_required' => false,
                'action_message' => ''
            ],
            // Rejected - 4
            config('constants.payment_statuses.rejected') => [
                'subject' => 'Payment Rejected',
                'status_text' => 'Rejected',
                'color' => '#DC2626', // Dark Red
                'background' => 'linear-gradient(135deg, #fff 0%, #fff 100%)',
                'icon' => '⛔',
                'message' => 'A payment request has been rejected.',
                'action_required' => false,
                'action_message' => 'The payment has been reviewed and rejected'
            ]
        ];
        // Return the config for the requested status, or fallback to pending if status not found
        return $configs[$paymentStatus] ?? $configs[config('constants.payment_statuses.pending')];
    }


    private function getPaymentTypeName($paymentType, $paymentStatus)
    {
        $type = 'Other';
        // Determine basic payment type
        if ($paymentType == config('constants.payment_types.bank')) {
            $type = 'Bank Transfer';
        } else if ($paymentType == config('constants.payment_types.stripe')) {
            $type = 'Stripe';
        } else if ($paymentType == config('constants.payment_types.pay_pal')) {
            $type = 'PayPal';
        }
        // Add status context for specific cases
        if (
            $paymentType == config('constants.payment_types.bank') &&
            $paymentStatus == config('constants.payment_statuses.pending')
        ) {
            $type .= ' (Pending)';
        } else if ($paymentStatus == config('constants.payment_statuses.failed')) {
            $type .= ' (Failed)';
        } else if ($paymentStatus == config('constants.payment_statuses.refunded')) {
            $type .= ' (Refunded)';
        } else if ($paymentStatus == config('constants.payment_statuses.rejected')) {
            $type .= ' (Rejected)';
        }
        return $type;
    }

    public function getTierEmployees($tierKeys, $query = null)
    {
        if (!$query) {
            $query = EmpCompanyDetails::query();
        }
        $tierIds = Tier::whereIn('tier_key', $tierKeys)->pluck('id')->toArray();
        $query->whereIn('tier_id', $tierIds);
        return $query;
    }

    function createConstructionRoles($customer_id, $workspace_id, $created_by = null)
    {
        // Roles are now global and managed by super admin
        // This function now only creates default team for customer/workspace
        $created_by = $created_by ?? $customer_id;

        // Create a default team if it doesn't exist
        $this->createDefaultTeam($customer_id, $workspace_id, $created_by);

        // Return empty array as roles are no longer created per customer
        return [];
    }

    /**
     * Create a default team if it doesn't exist
     */
    private function createDefaultTeam($customer_id, $workspace_id, $created_by = null)
    {
        $created_by = $created_by ?? $customer_id;

        // Check if a default team already exists for this customer/workspace
        $existingTeam = EmpTeam::where('customer_id', $customer_id)
            ->where('workspace_id', $workspace_id)
            ->where('del', '0')
            ->first();

        if (!$existingTeam) {
            // Create a default team with null supervisor (since employees might not exist yet)
            EmpTeam::create([
                'title' => 'Default Team',
                'supervisor' => null, // Will be updated later when employees are created
                'description' => 'Default team created automatically during role setup',
                'customer_id' => $customer_id,
                'workspace_id' => $workspace_id,
                'created_by' => $created_by,
                'del' => '0',
            ]);
        }
    }

    private function getSuperAdminId()
    {
        $superAdmin = User::where('user_type', config('constants.user_types.admin'))->first();
        return $superAdmin->id;
    }

    public function formatSystemDate($dateInput)
    {
        if (empty($dateInput)) {
            return null;
        }

        try {
            $dateFormat = $this->getSystemDateFormat();

            if ($dateInput instanceof Carbon) {
                $carbonDate = $dateInput;
            } elseif (is_numeric($dateInput)) {
                $carbonDate = Carbon::createFromTimestamp($dateInput);
            } elseif (is_string($dateInput)) {
                $carbonDate = Carbon::parse($dateInput);
            } else {
                return null; // Invalid input type
            }

            $formattedDate = $carbonDate->format($dateFormat);

            $time = $carbonDate->format('H:i:s');
            if ($time !== '00:00:00') {
                return $formattedDate . ' ' . $time; // Return date with time
            }

            return $formattedDate; // Return date only

        } catch (\Exception $e) {
            // Log error and return null
            Log::error('Date formatting error: ' . $e->getMessage(), [
                'input' => $dateInput,
            ]);
            return null;
        }
    }

    /**
     * Apply intelligent name search to a query
     * Handles full names, combinations, and partial matches
     * 
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @param string $searchTerm
     * @param string $relationName The relationship name (e.g., 'empPersonalDetails', 'empDetails')
     * @param array $nameFields Array of field names ['first_name', 'middle_name', 'last_name']
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function applyNameSearch($query, $searchTerm, $relationName = null, $nameFields = ['first_name', 'middle_name', 'last_name'])
    {
        if (!$relationName) {
            $relationName = 'empPersonalDetails';
        }
        return $query->whereHas($relationName, function ($subquery) use ($searchTerm, $nameFields) {
            $subquery->where(function ($nameQuery) use ($searchTerm, $nameFields) {
                // Split search term into words for full name search
                $nameParts = explode(' ', trim($searchTerm));

                if (count($nameParts) == 1) {
                    // Single word - search in any name field
                    $nameQuery->where($nameFields[0], 'like', '%' . $nameParts[0] . '%')
                        ->orWhere($nameFields[1], 'like', '%' . $nameParts[0] . '%')
                        ->orWhere($nameFields[2], 'like', '%' . $nameParts[0] . '%');
                } elseif (count($nameParts) == 2) {
                    // Two words - could be first+last or first+middle
                    $nameQuery->where(function ($twoWordQuery) use ($nameParts, $nameFields) {
                        $twoWordQuery->where($nameFields[0], 'like', '%' . $nameParts[0] . '%')
                            ->where($nameFields[2], 'like', '%' . $nameParts[1] . '%')
                            ->orWhere($nameFields[0], 'like', '%' . $nameParts[0] . '%')
                            ->where($nameFields[1], 'like', '%' . $nameParts[1] . '%');
                    });
                } elseif (count($nameParts) >= 3) {
                    // Three or more words - full name search
                    $nameQuery->where($nameFields[0], 'like', '%' . $nameParts[0] . '%')
                        ->where($nameFields[1], 'like', '%' . $nameParts[1] . '%')
                        ->where($nameFields[2], 'like', '%' . $nameParts[2] . '%');
                }

                // Also search for the full term in any field (for partial matches)
                $nameQuery->orWhere($nameFields[0], 'like', '%' . $searchTerm . '%')
                    ->orWhere($nameFields[1], 'like', '%' . $searchTerm . '%')
                    ->orWhere($nameFields[2], 'like', '%' . $searchTerm . '%');
            });
        });
    }

    /**
     * Get tier permissions for a specific module by module name
     * 
     * @param EmpCompanyDetails|User $employee The employee or user object
     * @param string $moduleName The name of the module (e.g., "Sites", "Roster", "Projects")
     * @return array|null Returns module permissions with sub_modules, or null if not found
     */
    protected function getTierPermissionsByModule($employee, $moduleName)
    {
        // Get tier_id from employee
        $tierId = null;
        if ($employee instanceof EmpCompanyDetails) {
            $tierId = $employee->tier_id;
        } elseif ($employee instanceof User) {
            // For customers, you might need to get tier differently
            // For now, return null for customers
            return null;
        }

        if (!$tierId) {
            return null;
        }

        // Get the module by name
        $module = DB::table('permissions_modules')
            ->where('title', $moduleName)
            ->where('del', 0)
            ->first(['id', 'title', 'image', 'link', 'priority']);

        if (!$module) {
            return null;
        }

        // Get module-level permission
        $modulePermission = DB::table('tier_permissions')
            ->where('tier_id', $tierId)
            ->where('module_id', $module->id)
            ->whereNull('sub_module_id')
            ->first(['view', 'maintain']);

        $modulePermissions = [
            'module_id' => $module->id,
            'module_name' => $module->title,
            'image' => $module->image,
            'link' => $module->link,
            'priority' => $module->priority,
            'view' => $modulePermission ? (int)$modulePermission->view : 0,
            'maintain' => $modulePermission ? (int)$modulePermission->maintain : 0,
            'sub_modules' => []
        ];

        // Get sub-modules if module has view or maintain permission
        if (!$modulePermission || $modulePermission->view || $modulePermission->maintain) {
            $subModuleIds = DB::table('permissions_sub_modules')
                ->where('module_id', $module->id)
                ->where('del', 0)
                ->pluck('id');

            $modulePermissions['sub_modules'] = DB::table('tier_permissions')
                ->where('tier_id', $tierId)
                ->whereIn('sub_module_id', $subModuleIds)
                ->where(function ($query) {
                    $query->where('view', 1)
                        ->orWhere('maintain', 1);
                })
                ->get()
                ->map(function ($permission) {
                    $subModule = DB::table('permissions_sub_modules')
                        ->where('id', $permission->sub_module_id)
                        ->first();

                    if (!$subModule) {
                        return null;
                    }

                    return [
                        'sub_module_id' => $subModule->id,
                        'sub_module_name' => $subModule->title,
                        'view' => (int)$permission->view,
                        'maintain' => (int)$permission->maintain,
                        'image' => $subModule->image,
                        'link' => $subModule->link,
                    ];
                })
                ->filter() // Remove null values
                ->values()
                ->toArray();
        }

        // Only return if module has permissions or has sub-modules
        if (($modulePermission && ($modulePermission->view || $modulePermission->maintain)) ||
            !empty($modulePermissions['sub_modules'])
        ) {
            return $modulePermissions;
        }

        return null;
    }

    /**
     * Get employee or subcontractor induction documents with signed and not signed status
     * 
     * @param int|null $employeeId The employee ID or subcontractor ID (if null, uses Auth::user() if employee)
     * @return array|null Returns array with 'signed' and 'not_signed' documents, or null if not an employee or subcontractor
     */
    public function getEmployeeInductionDocuments($employeeId = null)
    {
        $isSubcontractor = false;
        $employee = null;
        $subcontractor = null;
        $customerId = null;
        $workspaceId = null;
        $roleType = null;

        // If no employee ID provided, try to get from authenticated user
        if ($employeeId === null) {
            $userTable = $this->getUserTable();
            if ($userTable !== 'emp') {
                return null; // Not an employee
            }
            $employeeId = Auth::id();
        }

        // First, try to get employee details
        $employee = EmpCompanyDetails::withoutGlobalScope(\App\Scopes\NotDeletedScope::class)
            ->where('id', $employeeId)
            ->first();

        if ($employee) {
            $customerId = $employee->customer_id;
            $workspaceId = $employee->workspace_id;
            $roleType = $employee->user_type == 0 ? 'internal' : 'external';
        } else {
            // If not an employee, check if it's a subcontractor
            $subcontractor = \App\Models\LinkManagement::where('id', $employeeId)->first();
            
            if ($subcontractor) {
                $isSubcontractor = true;
                $customerId = $subcontractor->customer_id;
                $workspaceId = $subcontractor->workspace_id;
                $roleType = 'subcontractor';
            } else {
                return null; // Not an employee or subcontractor
            }
        }

        // Get all active induction documents for this customer/workspace
        $allDocuments = \App\Models\InductionDocument::where('customer_id', $customerId)
            ->where('workspace_id', $workspaceId)
            ->where('del', '0')
            ->where('is_active', true)
            ->orderBy('title')
            ->orderBy('version', 'desc')
            ->get();

        // Group by title and get only the latest version for each document
        $documents = [];
        foreach ($allDocuments as $doc) {
            $title = $doc->title;
            if (!isset($documents[$title])) {
                $documents[$title] = $doc;
            }
        }
        $documents = array_values($documents); // Convert to indexed array

        $signedDocuments = [];
        $notSignedDocuments = [];
        $validSignatures = [];
        $invalidSignatures = [];

        foreach ($documents as $doc) {
            $roleTypes = $doc->role_types ?? ['all'];
            
            // Check if employee/subcontractor matches role types
            if (!in_array('all', $roleTypes) && !in_array($roleType, $roleTypes)) {
                continue; // Skip if doesn't match role types
            }

            // Check for all signatures (both valid and invalid) for this document version
            $signatureQuery = \App\Models\InductionDocumentSignature::where('induction_document_id', $doc->id)
                ->where('document_version', $doc->version)
                ->where('del', '0');
            
            if ($isSubcontractor) {
                // Subcontractors use user_id field in signatures
                $signatureQuery->where('user_id', $employeeId);
            } else {
                // Employees use employee_id field in signatures
                $signatureQuery->where('employee_id', $employeeId);
            }
            
            // Get all signatures (valid and invalid)
            $allSignatures = $signatureQuery->get();
            
            // Get valid signature
            $validSignature = $allSignatures->where('is_valid', true)->first();
            
            // Get invalid signatures
            $invalidSignature = $allSignatures->where('is_valid', false)->first();

            $documentData = [
                'id' => $doc->id,
                'title' => $doc->title,
                'document_type' => $doc->document_type,
                'version' => $doc->version,
                'file_path' => $doc->file_path,
                'description' => $doc->description,
                'role_types' => $doc->role_types ?? [],
                'created_at' => $doc->created_at,
            ];

            if ($validSignature) {
                // Add signature details
                $documentData['signature'] = [
                    'id' => $validSignature->id,
                    'signature_path' => $validSignature->signature_path,
                    'signed_at' => $validSignature->signed_at,
                    'notes' => $validSignature->notes,
                    'is_valid' => $validSignature->is_valid,
                ];
                $signedDocuments[] = $documentData;
                $validSignatures[] = $documentData;
            } elseif ($invalidSignature) {
                // Document has invalid signature
                $documentData['signature'] = [
                    'id' => $invalidSignature->id,
                    'signature_path' => $invalidSignature->signature_path,
                    'signed_at' => $invalidSignature->signed_at,
                    'notes' => $invalidSignature->notes,
                    'is_valid' => $invalidSignature->is_valid,
                ];
                $invalidSignatures[] = $documentData;
                // Also add to not_signed since it's not valid
                $notSignedDocuments[] = $documentData;
            } else {
                // No signature at all
                $notSignedDocuments[] = $documentData;
            }
        }

        $totalValidSignatures = count($validSignatures);
        $totalInvalidSignatures = count($invalidSignatures);
        $totalSigned = count($signedDocuments);
        $totalNotSigned = count($notSignedDocuments);
        $totalDocuments = $totalSigned + $totalNotSigned;

        return [
            'signed' => $signedDocuments,
            'not_signed' => $notSignedDocuments,
            'valid_signatures' => $validSignatures,
            'invalid_signatures' => $invalidSignatures,
            'total_signed' => $totalSigned,
            'total_not_signed' => $totalNotSigned,
            'total_documents' => $totalDocuments,
            'total_valid_signatures' => $totalValidSignatures,
            'total_invalid_signatures' => $totalInvalidSignatures,
            'all_signatures_valid' => $totalInvalidSignatures === 0 && $totalValidSignatures > 0,
            'has_invalid_signatures' => $totalInvalidSignatures > 0,
            'all_documents_signed' => $totalNotSigned === 0,
        ];
    }
}
