<?php

class GalleryModel
{
    private static $cipher = 'AES-256-CBC';

    public static function getAllImages($user_id = null, $page = 1, $per_page = 20)
    {
        $database = DatabaseFactory::getFactory()->getConnection();
        $offset = ($page - 1) * $per_page;

        if ($user_id) {
            $sql = "SELECT g.*, u.user_name
                    FROM gallery g
                    JOIN users u ON g.user_id = u.user_id
                    WHERE g.user_id = :user_id
                    ORDER BY g.created_at DESC
                    LIMIT :offset, :per_page";
            $query = $database->prepare($sql);
            $query->bindParam(':user_id', $user_id, PDO::PARAM_INT);
        } else {
            $sql = "SELECT g.*, u.user_name
                    FROM gallery g
                    JOIN users u ON g.user_id = u.user_id
                    WHERE g.is_public = 1
                    ORDER BY g.created_at DESC
                    LIMIT :offset, :per_page";
            $query = $database->prepare($sql);
        }

        $query->bindParam(':offset', $offset, PDO::PARAM_INT);
        $query->bindParam(':per_page', $per_page, PDO::PARAM_INT);
        $query->execute();

        return $query->fetchAll(PDO::FETCH_OBJ);
    }

    public static function getImageCount($user_id = null)
    {
        $database = DatabaseFactory::getFactory()->getConnection();

        if ($user_id) {
            $sql = "SELECT COUNT(*) as count FROM gallery WHERE user_id = :user_id";
            $query = $database->prepare($sql);
            $query->execute(array(':user_id' => $user_id));
        } else {
            $sql = "SELECT COUNT(*) as count FROM gallery WHERE is_public = 1";
            $query = $database->prepare($sql);
            $query->execute();
        }

        $result = $query->fetch(PDO::FETCH_ASSOC);
        return (int)$result['count'];
    }

    public static function getImage($image_id)
    {
        $database = DatabaseFactory::getFactory()->getConnection();

        $sql = "SELECT g.*, u.user_name
                FROM gallery g
                JOIN users u ON g.user_id = u.user_id
                WHERE g.id = :image_id LIMIT 1";
        $query = $database->prepare($sql);
        $query->execute(array(':image_id' => $image_id));

        return $query->fetch(PDO::FETCH_OBJ);
    }

    public static function uploadImage($file, $title, $description, $is_public)
    {
        $user_id = Session::get('user_id');
        if (!$user_id) {
            Session::add('feedback_negative', 'You must be logged in to upload');
            return false;
        }

        $allowed_types = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
        if (!in_array($file['type'], $allowed_types)) {
            Session::add('feedback_negative', 'Invalid file type. Allowed: JPG, PNG, GIF, WebP');
            return false;
        }

        $max_size = 10 * 1024 * 1024;
        if ($file['size'] > $max_size) {
            Session::add('feedback_negative', 'File too large. Maximum size: 10MB');
            return false;
        }

        $image_data = file_get_contents($file['tmp_name']);
        if ($image_data === false) {
            Session::add('feedback_negative', 'Failed to read uploaded file');
            return false;
        }

        $thumb_data = self::createThumbnailData($file['tmp_name'], $file['type'], 300);
        if (!$thumb_data) {
            Session::add('feedback_negative', 'Failed to create thumbnail');
            return false;
        }

        $encryption_key = bin2hex(random_bytes(32));
        $iv = random_bytes(openssl_cipher_iv_length(self::$cipher));

        $encrypted_image = openssl_encrypt($image_data, self::$cipher, $encryption_key, OPENSSL_RAW_DATA, $iv);
        $encrypted_thumb = openssl_encrypt($thumb_data, self::$cipher, $encryption_key, OPENSSL_RAW_DATA, $iv);

        $encrypted_image = base64_encode($iv . $encrypted_image);
        $encrypted_thumb = base64_encode($iv . $encrypted_thumb);

        $upload_dir = dirname(__FILE__) . '/../../public/gallery_uploads/';
        if (!is_dir($upload_dir)) {
            mkdir($upload_dir, 0755, true);
        }

        $filename = uniqid('enc_') . '_' . time() . '.bin';
        $thumb_filename = 'thumb_' . $filename;

        if (file_put_contents($upload_dir . $filename, $encrypted_image) === false) {
            Session::add('feedback_negative', 'Failed to save encrypted image');
            return false;
        }

        if (file_put_contents($upload_dir . $thumb_filename, $encrypted_thumb) === false) {
            unlink($upload_dir . $filename);
            Session::add('feedback_negative', 'Failed to save encrypted thumbnail');
            return false;
        }

        try {
            $database = DatabaseFactory::getFactory()->getConnection();

            $sql = "INSERT INTO gallery (user_id, filename, thumb_filename, title, description, is_public, file_size, mime_type, encryption_key)
                    VALUES (:user_id, :filename, :thumb_filename, :title, :description, :is_public, :file_size, :mime_type, :encryption_key)";
            $query = $database->prepare($sql);
            $result = $query->execute(array(
                ':user_id' => $user_id,
                ':filename' => $filename,
                ':thumb_filename' => $thumb_filename,
                ':title' => $title ?: pathinfo($file['name'], PATHINFO_FILENAME),
                ':description' => $description,
                ':is_public' => $is_public ? 1 : 0,
                ':file_size' => $file['size'],
                ':mime_type' => $file['type'],
                ':encryption_key' => $encryption_key
            ));

            if ($result) {
                return $database->lastInsertId();
            }

            unlink($upload_dir . $filename);
            unlink($upload_dir . $thumb_filename);
            Session::add('feedback_negative', 'Failed to save to database');
            return false;

        } catch (PDOException $e) {
            unlink($upload_dir . $filename);
            unlink($upload_dir . $thumb_filename);
            Session::add('feedback_negative', 'Database error: ' . $e->getMessage());
            return false;
        }
    }

    public static function getDecryptedImage($image_id, $thumbnail = false)
    {
        $image = self::getImage($image_id);
        if (!$image) {
            return null;
        }

        $upload_dir = dirname(__FILE__) . '/../../public/gallery_uploads/';
        $filename = $thumbnail ? $image->thumb_filename : $image->filename;
        $filepath = $upload_dir . $filename;

        if (!file_exists($filepath)) {
            return null;
        }

        $encrypted_data = file_get_contents($filepath);
        if ($encrypted_data === false) {
            return null;
        }

        $encrypted_data = base64_decode($encrypted_data);
        $iv_length = openssl_cipher_iv_length(self::$cipher);
        $iv = substr($encrypted_data, 0, $iv_length);
        $encrypted_data = substr($encrypted_data, $iv_length);

        $decrypted = openssl_decrypt($encrypted_data, self::$cipher, $image->encryption_key, OPENSSL_RAW_DATA, $iv);

        return array(
            'data' => $decrypted,
            'mime_type' => $image->mime_type
        );
    }

    public static function updateImage($image_id, $title, $description, $is_public)
    {
        $user_id = Session::get('user_id');
        $database = DatabaseFactory::getFactory()->getConnection();

        $sql = "UPDATE gallery SET title = :title, description = :description, is_public = :is_public
                WHERE id = :image_id AND user_id = :user_id";
        $query = $database->prepare($sql);
        return $query->execute(array(
            ':image_id' => $image_id,
            ':user_id' => $user_id,
            ':title' => $title,
            ':description' => $description,
            ':is_public' => $is_public ? 1 : 0
        ));
    }

    public static function deleteImage($image_id)
    {
        $user_id = Session::get('user_id');
        $image = self::getImage($image_id);

        if (!$image || $image->user_id != $user_id) {
            return false;
        }

        $upload_dir = dirname(__FILE__) . '/../../public/gallery_uploads/';
        $filepath = $upload_dir . $image->filename;
        $thumbpath = $upload_dir . $image->thumb_filename;

        if (file_exists($filepath)) {
            unlink($filepath);
        }
        if (file_exists($thumbpath)) {
            unlink($thumbpath);
        }

        $database = DatabaseFactory::getFactory()->getConnection();

        $sql = "DELETE FROM gallery WHERE id = :image_id AND user_id = :user_id";
        $query = $database->prepare($sql);
        return $query->execute(array(':image_id' => $image_id, ':user_id' => $user_id));
    }

    private static function createThumbnailData($source, $mime_type, $max_size)
    {
        $image_info = getimagesize($source);
        if (!$image_info) {
            return false;
        }

        $width = $image_info[0];
        $height = $image_info[1];
        $type = $image_info[2];

        switch ($type) {
            case IMAGETYPE_JPEG:
                $image = imagecreatefromjpeg($source);
                break;
            case IMAGETYPE_PNG:
                $image = imagecreatefrompng($source);
                break;
            case IMAGETYPE_GIF:
                $image = imagecreatefromgif($source);
                break;
            case IMAGETYPE_WEBP:
                $image = imagecreatefromwebp($source);
                break;
            default:
                return false;
        }

        if (!$image) {
            return false;
        }

        $ratio = min($max_size / $width, $max_size / $height);
        if ($ratio >= 1) {
            $new_width = $width;
            $new_height = $height;
        } else {
            $new_width = (int)($width * $ratio);
            $new_height = (int)($height * $ratio);
        }

        $thumb = imagecreatetruecolor($new_width, $new_height);

        if ($type == IMAGETYPE_PNG || $type == IMAGETYPE_GIF) {
            imagealphablending($thumb, false);
            imagesavealpha($thumb, true);
            $transparent = imagecolorallocatealpha($thumb, 0, 0, 0, 127);
            imagefilledrectangle($thumb, 0, 0, $new_width, $new_height, $transparent);
        }

        imagecopyresampled($thumb, $image, 0, 0, 0, 0, $new_width, $new_height, $width, $height);

        ob_start();
        switch ($type) {
            case IMAGETYPE_JPEG:
                imagejpeg($thumb, null, 85);
                break;
            case IMAGETYPE_PNG:
                imagepng($thumb, null, 8);
                break;
            case IMAGETYPE_GIF:
                imagegif($thumb);
                break;
            case IMAGETYPE_WEBP:
                imagewebp($thumb, null, 85);
                break;
        }
        $thumb_data = ob_get_clean();

        return $thumb_data;
    }

    public static function formatFileSize($bytes)
    {
        if ($bytes >= 1048576) {
            return number_format($bytes / 1048576, 2) . ' MB';
        } elseif ($bytes >= 1024) {
            return number_format($bytes / 1024, 2) . ' KB';
        }
        return $bytes . ' bytes';
    }
}
