<?php
/**
 * ZLO Platform - Upload Controller
 */

declare(strict_types=1);

require_once __DIR__ . '/../core/Router.php';

class UploadController
{
    private Database $db;
    private Security $security;
    private array $config;
    
    public function __construct()
    {
        $this->db = new Database();
        $this->security = new Security();
        $this->config = require __DIR__ . '/../config/config.php';
    }
    
    /**
     * Upload file (admin only)
     */
    public function upload(array $params): array
    {
        AuthController::requireAuth();
        
        // Check if file was uploaded
        if (empty($_FILES['file'])) {
            http_response_code(400);
            return ['error' => 'No file uploaded'];
        }
        
        $file = $_FILES['file'];
        $uploadConfig = $this->config['uploads'];
        
        // Verify upload
        $allowedTypes = $uploadConfig['allowed_types'];
        $maxSize = $uploadConfig['max_size'];
        
        $verification = $this->security->verifyUpload($file, $allowedTypes, $maxSize);
        
        if (!$verification['valid']) {
            http_response_code(400);
            return ['error' => 'Upload failed', 'details' => $verification['errors']];
        }
        
        // Generate safe filename
        $extension = $verification['extension'];
        $filename = $this->security->generateFilename($file['name'], $extension);
        
        // Determine file type
        $fileType = $this->getFileType($extension);
        
        // Create upload directory if needed
        $uploadPath = $uploadConfig['path'] . $fileType . 's/';
        $this->security->ensureDirectory($uploadPath);
        
        // Move uploaded file
        $destination = $uploadPath . $filename;
        
        if (!move_uploaded_file($file['tmp_name'], $destination)) {
            http_response_code(500);
            return ['error' => 'Failed to save file'];
        }
        
        // Get image dimensions if applicable
        $dimensions = null;
        if ($fileType === 'image') {
            $imageInfo = getimagesize($destination);
            if ($imageInfo) {
                $dimensions = $imageInfo[0] . 'x' . $imageInfo[1];
                
                // Generate thumbnails
                $this->generateThumbnails($destination, $filename, $extension);
            }
        }
        
        // Save to database
        $user = (new AuthController())->getAuthenticatedUser();
        
        $mediaData = [
            'file_name' => $filename,
            'original_name' => $file['name'],
            'file_path' => $fileType . 's/' . $filename,
            'file_type' => $fileType,
            'mime_type' => $verification['mime_type'],
            'file_size' => $file['size'],
            'dimensions' => $dimensions,
            'uploaded_by' => $user['id'],
            'created_at' => date('Y-m-d H:i:s')
        ];
        
        try {
            $id = $this->db->insert('media', $mediaData);
            
            http_response_code(201);
            return [
                'id' => $id,
                'file_name' => $filename,
                'original_name' => $file['name'],
                'url' => $uploadConfig['url_path'] . $fileType . 's/' . $filename,
                'file_type' => $fileType,
                'size' => $file['size']
            ];
        } catch (Exception $e) {
            // Delete file if database insert fails
            unlink($destination);
            http_response_code(500);
            return ['error' => 'Failed to save file information'];
        }
    }
    
    /**
     * Get all uploads (admin only)
     */
    public function index(array $params): array
    {
        AuthController::requireAuth();
        
        $query = Router::getQuery();
        
        $fileType = $query['type'] ?? null;
        $page = (int) ($query['page'] ?? 1);
        $limit = (int) ($query['limit'] ?? 20);
        
        $sql = "SELECT m.*, u.name as uploaded_by_name 
                FROM media m 
                LEFT JOIN users u ON m.uploaded_by = u.id 
                WHERE 1=1";
        $params = [];
        
        if ($fileType) {
            $sql .= " AND m.file_type = ?";
            $params[] = $fileType;
        }
        
        $sql .= " ORDER BY m.created_at DESC LIMIT ? OFFSET ?";
        $params[] = $limit;
        $params[] = ($page - 1) * $limit;
        
        $files = $this->db->fetchAll($sql, $params);
        
        // Add full URL
        $uploadConfig = $this->config['uploads'];
        foreach ($files as &$file) {
            $file['url'] = $uploadConfig['url_path'] . $file['file_path'];
        }
        
        return [
            'files' => $files,
            'pagination' => [
                'current_page' => $page,
                'per_page' => $limit
            ]
        ];
    }
    
    /**
     * Delete upload (admin only)
     */
    public function delete(array $params): array
    {
        AuthController::requirePermission('settings.edit');
        
        $id = (int) ($params['id'] ?? 0);
        
        if (!$id) {
            http_response_code(400);
            return ['error' => 'File ID is required'];
        }
        
        // Get file info
        $sql = "SELECT * FROM media WHERE id = ?";
        $file = $this->db->fetchOne($sql, [$id]);
        
        if (!$file) {
            http_response_code(404);
            return ['error' => 'File not found'];
        }
        
        // Delete physical file
        $uploadConfig = $this->config['uploads'];
        $filePath = $uploadConfig['path'] . $file['file_path'];
        
        if (file_exists($filePath)) {
            unlink($filePath);
        }
        
        // Delete thumbnails if image
        if ($file['file_type'] === 'image') {
            foreach (['thumbnail', 'medium', 'large'] as $size) {
                $thumbPath = $uploadConfig['path'] . $file['file_type'] . 's/' . $size . '_' . $file['file_name'];
                if (file_exists($thumbPath)) {
                    unlink($thumbPath);
                }
            }
        }
        
        // Delete from database
        try {
            $this->db->delete('media', "id = ?", [$id]);
            return ['message' => 'File deleted successfully'];
        } catch (Exception $e) {
            http_response_code(500);
            return ['error' => 'Failed to delete file'];
        }
    }
    
    /**
     * Get file type from extension
     */
    private function getFileType(string $extension): string
    {
        $extension = strtolower($extension);
        
        foreach ($this->config['uploads']['allowed_types'] as $type => $extensions) {
            if (in_array($extension, $extensions)) {
                return $type;
            }
        }
        
        return 'document';
    }
    
    /**
     * Generate thumbnails for images
     */
    private function generateThumbnails(string $sourcePath, string $filename, string $extension): void
    {
        $uploadConfig = $this->config['uploads'];
        $imageSizes = $uploadConfig['image_sizes'];
        
        $dir = dirname($sourcePath) . '/';
        
        foreach ($imageSizes as $sizeName => $dimensions) {
            list($width, $height) = $dimensions;
            
            $thumbPath = $dir . $sizeName . '_' . $filename;
            
            // Create thumbnail using GD
            $this->createThumbnail($sourcePath, $thumbPath, $width, $height, $extension);
        }
    }
    
    /**
     * Create thumbnail using GD
     */
    private function createThumbnail(string $source, string $destination, int $maxWidth, int $maxHeight, string $extension): bool
    {
        // Get source image dimensions
        list($srcWidth, $srcHeight) = getimagesize($source);
        
        // Calculate new dimensions
        $ratio = min($maxWidth / $srcWidth, $maxHeight / $srcHeight);
        $newWidth = (int) ($srcWidth * $ratio);
        $newHeight = (int) ($srcHeight * $ratio);
        
        // Create source image
        switch (strtolower($extension)) {
            case 'jpg':
            case 'jpeg':
                $srcImage = imagecreatefromjpeg($source);
                break;
            case 'png':
                $srcImage = imagecreatefrompng($source);
                break;
            case 'gif':
                $srcImage = imagecreatefromgif($source);
                break;
            case 'webp':
                $srcImage = imagecreatefromwebp($source);
                break;
            default:
                return false;
        }
        
        if (!$srcImage) {
            return false;
        }
        
        // Create destination image
        $dstImage = imagecreatetruecolor($newWidth, $newHeight);
        
        // Preserve transparency for PNG
        if ($extension === 'png') {
            imagealphablending($dstImage, false);
            imagesavealpha($dstImage, true);
        }
        
        // Resize
        imagecopyresampled($dstImage, $srcImage, 0, 0, 0, 0, $newWidth, $newHeight, $srcWidth, $srcHeight);
        
        // Save
        switch (strtolower($extension)) {
            case 'jpg':
            case 'jpeg':
                imagejpeg($dstImage, $destination, 85);
                break;
            case 'png':
                imagepng($dstImage, $destination, 8);
                break;
            case 'gif':
                imagegif($dstImage, $destination);
                break;
            case 'webp':
                imagewebp($dstImage, $destination, 85);
                break;
        }
        
        // Clean up
        imagedestroy($srcImage);
        imagedestroy($dstImage);
        
        return true;
    }
}
