<?php
/**
 * ============================================================
 * FILE UPLOAD HANDLER
 * ============================================================
 * Secure file upload handling for product images
 */

class Upload {
    private array $errors = [];
    private array $uploadedFiles = [];
    
    /**
     * Upload single file
     * @param array $file $_FILES array element
     * @param string $destination Relative path from UPLOAD_PATH
     * @param array $options
     * @return string|null Filename on success, null on failure
     */
    public function single(array $file, string $destination, array $options = []): ?string {
        $options = array_merge([
            'allowed_types' => ALLOWED_IMAGE_TYPES,
            'allowed_extensions' => ALLOWED_IMAGE_EXTENSIONS,
            'max_size' => MAX_FILE_SIZE,
            'rename' => true
        ], $options);
        
        // Check for upload errors
        if ($file['error'] !== UPLOAD_ERR_OK) {
            $this->errors[] = $this->getUploadError($file['error']);
            return null;
        }
        
        // Validate file size
        if ($file['size'] > $options['max_size']) {
            $maxMB = round($options['max_size'] / (1024 * 1024), 1);
            $this->errors[] = "ফাইল সাইজ সর্বোচ্চ {$maxMB}MB হতে পারবে";
            return null;
        }
        
        // Validate MIME type
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mimeType = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);
        
        if (!in_array($mimeType, $options['allowed_types'])) {
            $this->errors[] = "এই ফাইল টাইপ সমর্থিত নয়: {$mimeType}";
            return null;
        }
        
        // Validate extension
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($extension, $options['allowed_extensions'])) {
            $this->errors[] = "এই এক্সটেনশন সমর্থিত নয়: {$extension}";
            return null;
        }
        
        // Create destination directory if not exists
        $uploadDir = UPLOAD_PATH . '/' . trim($destination, '/');
        if (!is_dir($uploadDir)) {
            if (!mkdir($uploadDir, 0755, true)) {
                $this->errors[] = "আপলোড ফোল্ডার তৈরি করা যায়নি";
                return null;
            }
        }
        
        // Generate filename
        if ($options['rename']) {
            $filename = $this->generateFilename($extension);
        } else {
            $filename = $this->sanitizeFilename($file['name']);
        }
        
        // Full path
        $fullPath = $uploadDir . '/' . $filename;
        
        // Move file
        if (!move_uploaded_file($file['tmp_name'], $fullPath)) {
            $this->errors[] = "ফাইল আপলোড ব্যর্থ হয়েছে";
            return null;
        }
        
        return $filename;
    }
    
    /**
     * Upload multiple files
     * @param array $files $_FILES array with multiple files
     * @param string $destination
     * @param array $options
     * @return array Array of uploaded filenames
     */
    public function multiple(array $files, string $destination, array $options = []): array {
        $uploaded = [];
        
        // Reorganize files array if needed
        if (isset($files['name']) && is_array($files['name'])) {
            $fileCount = count($files['name']);
            
            for ($i = 0; $i < $fileCount; $i++) {
                if ($files['error'][$i] === UPLOAD_ERR_NO_FILE) {
                    continue;
                }
                
                $file = [
                    'name'     => $files['name'][$i],
                    'type'     => $files['type'][$i],
                    'tmp_name' => $files['tmp_name'][$i],
                    'error'    => $files['error'][$i],
                    'size'     => $files['size'][$i]
                ];
                
                $result = $this->single($file, $destination, $options);
                if ($result) {
                    $uploaded[] = $result;
                }
            }
        }
        
        $this->uploadedFiles = $uploaded;
        return $uploaded;
    }
    
    /**
     * Generate unique filename
     * @param string $extension
     * @return string
     */
    private function generateFilename(string $extension): string {
        return date('Ymd') . '_' . uniqid() . '_' . bin2hex(random_bytes(4)) . '.' . $extension;
    }
    
    /**
     * Sanitize original filename
     * @param string $filename
     * @return string
     */
    private function sanitizeFilename(string $filename): string {
        // Remove directory paths
        $filename = basename($filename);
        // Remove special characters
        $filename = preg_replace('/[^a-zA-Z0-9._-]/', '_', $filename);
        // Add timestamp to avoid conflicts
        $ext = pathinfo($filename, PATHINFO_EXTENSION);
        $name = pathinfo($filename, PATHINFO_FILENAME);
        return $name . '_' . time() . '.' . $ext;
    }
    
    /**
     * Get upload error message
     * @param int $errorCode
     * @return string
     */
    private function getUploadError(int $errorCode): string {
        $errors = [
            UPLOAD_ERR_INI_SIZE   => 'ফাইল সাইজ সার্ভার লিমিট অতিক্রম করেছে',
            UPLOAD_ERR_FORM_SIZE  => 'ফাইল সাইজ ফর্ম লিমিট অতিক্রম করেছে',
            UPLOAD_ERR_PARTIAL    => 'ফাইল আংশিক আপলোড হয়েছে',
            UPLOAD_ERR_NO_FILE    => 'কোনো ফাইল সিলেক্ট করা হয়নি',
            UPLOAD_ERR_NO_TMP_DIR => 'টেম্পোরারি ফোল্ডার পাওয়া যায়নি',
            UPLOAD_ERR_CANT_WRITE => 'ডিস্কে লেখা যায়নি',
            UPLOAD_ERR_EXTENSION  => 'এক্সটেনশন দ্বারা বাধা পেয়েছে'
        ];
        
        return $errors[$errorCode] ?? 'অজানা আপলোড ত্রুটি';
    }
    
    /**
     * Delete file
     * @param string $path Relative path from UPLOAD_PATH
     * @return bool
     */
    public static function delete(string $path): bool {
        $fullPath = UPLOAD_PATH . '/' . ltrim($path, '/');
        if (file_exists($fullPath)) {
            return unlink($fullPath);
        }
        return false;
    }
    
    /**
     * Check if file exists
     * @param string $path
     * @return bool
     */
    public static function exists(string $path): bool {
        $fullPath = UPLOAD_PATH . '/' . ltrim($path, '/');
        return file_exists($fullPath);
    }
    
    /**
     * Get errors
     * @return array
     */
    public function getErrors(): array {
        return $this->errors;
    }
    
    /**
     * Check if has errors
     * @return bool
     */
    public function hasErrors(): bool {
        return !empty($this->errors);
    }
    
    /**
     * Get first error
     * @return string|null
     */
    public function getFirstError(): ?string {
        return $this->errors[0] ?? null;
    }
    
    /**
     * Get uploaded files
     * @return array
     */
    public function getUploadedFiles(): array {
        return $this->uploadedFiles;
    }
}
