<?php

class FileUploadService
{

    private $uploadPath;
    private $allowedTypes;
    private $maxSize;

    public function __construct($uploadPath = null, $allowedTypes = null, $maxSize = null)
    {
        $this->uploadPath = $uploadPath ?: __DIR__ . '/../uploads/';
        $this->allowedTypes = $allowedTypes ?: ['jpg', 'jpeg', 'png', 'gif', 'webp'];
        $this->maxSize = $maxSize ?: 2 * 1024 * 1024; // 2MB default
    }

    /**
     * Upload a file
     */
    public function uploadFile($file, $subfolder = '', $customName = null)
    {
        try {
            // Validate file
            $validation = $this->validateFile($file);
            if (!$validation['valid']) {
                return ['success' => false, 'message' => $validation['message']];
            }

            // Create upload directory
            $targetDir = $this->uploadPath . $subfolder;
            if (!empty($subfolder) && !file_exists($targetDir)) {
                if (!mkdir($targetDir, 0755, true)) {
                    return ['success' => false, 'message' => 'Failed to create upload directory'];
                }
            }

            // Generate filename
            $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
            if ($customName) {
                $filename = $customName . '.' . $extension;
            } else {
                $filename = $this->generateUniqueFilename($file['name']);
            }

            $targetFile = $targetDir . '/' . $filename;

            // Move uploaded file
            if (move_uploaded_file($file['tmp_name'], $targetFile)) {
                $relativePath = ltrim(str_replace($this->uploadPath, '', $targetFile), '/');

                return [
                    'success' => true,
                    'message' => 'File uploaded successfully',
                    'filename' => $filename,
                    'path' => $targetFile,
                    'relative_path' => $relativePath,
                    'url' => $this->getFileUrl($relativePath),
                    'size' => filesize($targetFile)
                ];
            } else {
                return ['success' => false, 'message' => 'Failed to move uploaded file'];
            }
        } catch (Exception $e) {
            return ['success' => false, 'message' => 'Upload error: ' . $e->getMessage()];
        }
    }

    /**
     * Upload multiple files
     */
    public function uploadMultipleFiles($files, $subfolder = '')
    {
        $results = [];

        foreach ($files as $index => $file) {
            $results[$index] = $this->uploadFile($file, $subfolder);
        }

        return $results;
    }

    /**
     * Validate file
     */
    public function validateFile($file)
    {
        // Check for upload errors
        if ($file['error'] !== UPLOAD_ERR_OK) {
            return ['valid' => false, 'message' => $this->getUploadErrorMessage($file['error'])];
        }

        // Check file size
        if ($file['size'] > $this->maxSize) {
            $maxSizeMB = $this->maxSize / (1024 * 1024);
            return ['valid' => false, 'message' => "File size exceeds maximum allowed size of {$maxSizeMB}MB"];
        }

        // Check file extension
        $extension = strtolower(pathinfo($file['name'], PATHINFO_EXTENSION));
        if (!in_array($extension, $this->allowedTypes)) {
            $allowedTypesStr = implode(', ', $this->allowedTypes);
            return ['valid' => false, 'message' => "File type not allowed. Allowed types: {$allowedTypesStr}"];
        }

        // Check MIME type
        $finfo = finfo_open(FILEINFO_MIME_TYPE);
        $mimeType = finfo_file($finfo, $file['tmp_name']);
        finfo_close($finfo);

        $allowedMimeTypes = [
            'jpg' => 'image/jpeg',
            'jpeg' => 'image/jpeg',
            'png' => 'image/png',
            'gif' => 'image/gif',
            'webp' => 'image/webp'
        ];

        if (isset($allowedMimeTypes[$extension]) && $mimeType !== $allowedMimeTypes[$extension]) {
            return ['valid' => false, 'message' => 'File type validation failed'];
        }

        return ['valid' => true, 'message' => 'File is valid'];
    }

    /**
     * Generate unique filename
     */
    private function generateUniqueFilename($originalName)
    {
        $extension = strtolower(pathinfo($originalName, PATHINFO_EXTENSION));
        $basename = pathinfo($originalName, PATHINFO_FILENAME);
        $basename = preg_replace('/[^a-zA-Z0-9_-]/', '_', $basename);

        return $basename . '_' . date('YmdHis') . '_' . uniqid() . '.' . $extension;
    }

    /**
     * Get file URL
     */
    private function getFileUrl($relativePath)
    {
        $protocol = isset($_SERVER['HTTPS']) && $_SERVER['HTTPS'] === 'on' ? 'https' : 'http';
        $host = $_SERVER['HTTP_HOST'] ?? 'localhost';
        $scriptPath = dirname($_SERVER['SCRIPT_NAME']);

        return $protocol . '://' . $host . $scriptPath . '/uploads/' . $relativePath;
    }

    /**
     * Get upload error message
     */
    private function getUploadErrorMessage($errorCode)
    {
        switch ($errorCode) {
            case UPLOAD_ERR_INI_SIZE:
            case UPLOAD_ERR_FORM_SIZE:
                return 'File size is too large';
            case UPLOAD_ERR_PARTIAL:
                return 'File was only partially uploaded';
            case UPLOAD_ERR_NO_FILE:
                return 'No file was uploaded';
            case UPLOAD_ERR_NO_TMP_DIR:
                return 'Missing temporary folder';
            case UPLOAD_ERR_CANT_WRITE:
                return 'Failed to write file to disk';
            case UPLOAD_ERR_EXTENSION:
                return 'File upload stopped by extension';
            default:
                return 'Unknown upload error';
        }
    }

    /**
     * Delete file
     */
    public function deleteFile($filePath)
    {
        if (file_exists($filePath)) {
            return unlink($filePath);
        }
        return false;
    }

    /**
     * Get file info
     */
    public function getFileInfo($filePath)
    {
        if (!file_exists($filePath)) {
            return null;
        }

        return [
            'size' => filesize($filePath),
            'modified' => filemtime($filePath),
            'extension' => strtolower(pathinfo($filePath, PATHINFO_EXTENSION)),
            'filename' => basename($filePath),
            'mime_type' => mime_content_type($filePath)
        ];
    }

    /**
     * Set allowed file types
     */
    public function setAllowedTypes($types)
    {
        $this->allowedTypes = $types;
    }

    /**
     * Set maximum file size
     */
    public function setMaxSize($size)
    {
        $this->maxSize = $size;
    }

    /**
     * Set upload path
     */
    public function setUploadPath($path)
    {
        $this->uploadPath = rtrim($path, '/') . '/';
    }
}
