<?php
/**
 * Image Uploader with EXIF Date Extraction (Multi-File Support)
 * 
 * Features:
 * - Mutiple Files Upload
 * - Specific Naming Convention: <Date> - <Description>.<Extension>
 * - Date from EXIF "DateTimeOriginal"
 * - Max size 15MB per file
 * - Live Countdown & Progress Bar
 * - Modern Dark UI
 */

// EVENT CONFIGURATION
const EVENT_NAME = 'Event Bilder Upload';
const EVENT_SUBTITLE = 'Speichere deine Momente datumsgerecht.';

// DEADLINE CONFIGURATION
// Format: YYYY-MM-DD HH:MM:SS
const UPLOAD_DEADLINE = '2026-11-30 23:59:59';

// Timezone
date_default_timezone_set('Europe/Berlin');

$messages = []; // Array to store status messages for each file

// Maximum file size in bytes (15 MB)
const MAX_FILE_SIZE = 15 * 1024 * 1024;

if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    header('Content-Type: application/json');
    $responseMessages = [];

    // Check Deadline
    if (time() > strtotime(UPLOAD_DEADLINE)) {
        echo json_encode([
            'status' => 'error',
            'messages' => [['type' => 'error', 'text' => 'Der Upload-Zeitraum ist abgelaufen.']]
        ]);
        exit;
    }

    $targetDir = __DIR__ . "/images/";

    // Ensure directory exists
    if (!is_dir($targetDir)) {
        if (!@mkdir($targetDir, 0755, true)) {
            $errorInfo = error_get_last();
            $sysError = $errorInfo ? $errorInfo['message'] : 'Unbekannter Fehler';
            echo json_encode([
                'status' => 'error',
                'messages' => [['type' => 'error', 'text' => "Server-Fehler: Konnte Verzeichnis 'images' nicht erstellen. ($sysError)"]]
            ]);
            exit;
        }
    }

    if (isset($_FILES['images'])) {
        $fileCount = count($_FILES['images']['name']);
        $descriptions = $_POST['descriptions'] ?? [];

        for ($i = 0; $i < $fileCount; $i++) {
            $fileName = $_FILES['images']['name'][$i];
            $fileTmpPath = $_FILES['images']['tmp_name'][$i];
            $fileSize = $_FILES['images']['size'][$i];
            $fileError = $_FILES['images']['error'][$i];
            $description = trim($descriptions[$i] ?? '');

            // Context prefix for messages
            $msgPrefix = "<strong>$fileName</strong>: ";

            // Validate Description
            $descriptionSafe = preg_replace('/[^a-zA-Z0-9\-_äöüÄÖÜß ]/u', '', $description);
            $descriptionSafe = trim(preg_replace('/\s+/', ' ', $descriptionSafe));

            if (empty($descriptionSafe)) {
                $responseMessages[] = ['type' => 'error', 'text' => $msgPrefix . "Keine gültige Beschreibung."];
                continue;
            }

            if ($fileError !== UPLOAD_ERR_OK) {
                $errorMessages = [
                    UPLOAD_ERR_INI_SIZE => 'Datei zu groß (server limit).',
                    UPLOAD_ERR_FORM_SIZE => 'Datei zu groß (form limit).',
                    UPLOAD_ERR_PARTIAL => 'Nur teilweise hochgeladen.',
                    UPLOAD_ERR_NO_FILE => 'Keine Datei.',
                    UPLOAD_ERR_NO_TMP_DIR => 'Temporärer Ordner fehlt.',
                    UPLOAD_ERR_CANT_WRITE => 'Schreibfehler.',
                ];
                $err = $errorMessages[$fileError] ?? "Fehler Code $fileError";
                $responseMessages[] = ['type' => 'error', 'text' => $msgPrefix . $err];
                continue;
            }

            if ($fileSize > MAX_FILE_SIZE) {
                $responseMessages[] = ['type' => 'error', 'text' => $msgPrefix . "Größer als 15MB."];
                continue;
            }

            // Extension Check
            $fileNameCmps = explode(".", $fileName);
            $fileExtension = strtolower(end($fileNameCmps));
            $allowedExtensions = ['jpg', 'jpeg', 'png', 'gif', 'webp', 'tiff', 'heic'];

            if (!in_array($fileExtension, $allowedExtensions)) {
                $responseMessages[] = ['type' => 'error', 'text' => $msgPrefix . "Format nicht erlaubt."];
                continue;
            }

            // Exif Date
            $dateStr = null;
            if (function_exists('exif_read_data')) {
                $exif = @exif_read_data($fileTmpPath);
                if ($exif && !empty($exif['DateTimeOriginal'])) {
                    $dateTimeObj = DateTime::createFromFormat('Y:m:d H:i:s', $exif['DateTimeOriginal']);
                    if ($dateTimeObj) {
                        $dateStr = $dateTimeObj->format('d-m-Y');
                    }
                }
            }
            if (!$dateStr) {
                $dateStr = date('d-m-Y');
            }

            // Construct Target Path
            $newFileName = "{$dateStr} - {$descriptionSafe}.{$fileExtension}";
            $dest_path = $targetDir . $newFileName;

            // Handle Duplicates
            $counter = 1;
            $info = pathinfo($dest_path);
            while (file_exists($dest_path)) {
                $dest_path = $info['dirname'] . '/' . $info['filename'] . " ($counter)." . $info['extension'];
                $newFileName = basename($dest_path);
                $counter++;
            }

            if (move_uploaded_file($fileTmpPath, $dest_path)) {
                $responseMessages[] = ['type' => 'success', 'text' => $msgPrefix . "Gespeichert als \"$newFileName\"."];
            } else {
                $errorInfo = error_get_last();
                $sysError = $errorInfo ? $errorInfo['message'] : 'Unbekannter Fehler';
                $responseMessages[] = ['type' => 'error', 'text' => $msgPrefix . "Upload gescheitert: $sysError"];
            }
        }
    }

    echo json_encode(['status' => 'done', 'messages' => $responseMessages]);
    exit;
}
?>
<!DOCTYPE html>
<html lang="de">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title><?= htmlspecialchars(EVENT_NAME) ?></title>
    <link rel="preconnect" href="https://fonts.googleapis.com">
    <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600&display=swap" rel="stylesheet">
    <style>
        :root {
            --bg-color: #f5f3f0;
            --card-bg: #ffffff;
            --text-main: #2c2c2c;
            --text-muted: #7a7a7a;
            --primary: #4a4a4a;
            --primary-hover: #333333;
            --accent: #6b7b6e;
            --success: #5a7a5e;
            --error: #a0503c;
            --border: #ddd8d2;
            --border-focus: #b0aaa2;
            --input-bg: #faf9f7;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
            font-family: 'Inter', -apple-system, BlinkMacSystemFont, sans-serif;
        }

        body {
            background-color: var(--bg-color);
            color: var(--text-main);
            min-height: 100vh;
            display: flex;
            align-items: flex-start;
            justify-content: center;
            padding: 40px 20px;
        }

        .container {
            width: 100%;
            max-width: 720px;
            background: var(--card-bg);
            border: 1px solid var(--border);
            border-radius: 12px;
            padding: 40px;
            box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06);
        }

        h1 {
            font-size: 24px;
            font-weight: 600;
            margin-bottom: 6px;
            text-align: center;
            color: var(--text-main);
        }

        p.subtitle {
            text-align: center;
            color: var(--text-muted);
            margin-bottom: 24px;
            font-size: 15px;
        }

        /* Countdown */
        .countdown-box {
            text-align: center;
            background: var(--input-bg);
            border: 1px solid var(--border);
            padding: 16px;
            border-radius: 8px;
            margin-bottom: 28px;
            color: var(--text-main);
            font-size: 20px;
            font-weight: 600;
            font-variant-numeric: tabular-nums;
            transition: color 0.3s ease;
        }

        /* Batch Controls */
        .batch-controls {
            background: var(--input-bg);
            padding: 16px;
            border-radius: 8px;
            border: 1px solid var(--border);
            margin-bottom: 24px;
            display: flex;
            gap: 12px;
            align-items: flex-end;
        }

        .form-group-batch {
            flex: 1;
        }

        .form-group-batch label {
            display: block;
            margin-bottom: 6px;
            font-size: 12px;
            color: var(--text-muted);
            text-transform: uppercase;
            letter-spacing: 0.5px;
            font-weight: 500;
        }

        input[type="text"] {
            width: 100%;
            padding: 10px 14px;
            background: var(--card-bg);
            border: 1px solid var(--border);
            border-radius: 6px;
            color: var(--text-main);
            font-size: 14px;
            transition: border-color 0.2s;
            outline: none;
        }

        input[type="text"]::placeholder {
            color: #b0aaa2;
        }

        input[type="text"]:focus {
            border-color: var(--border-focus);
        }

        .btn-secondary {
            padding: 10px 18px;
            background: var(--card-bg);
            border: 1px solid var(--border);
            color: var(--text-main);
            border-radius: 6px;
            cursor: pointer;
            font-size: 14px;
            font-weight: 500;
            transition: border-color 0.2s;
            white-space: nowrap;
        }

        .btn-secondary:hover {
            border-color: var(--border-focus);
        }

        /* Drop Area */
        .file-drop-area {
            position: relative;
            display: flex;
            align-items: center;
            justify-content: center;
            flex-direction: column;
            width: 100%;
            padding: 36px;
            border: 2px dashed var(--border);
            border-radius: 8px;
            background: var(--input-bg);
            transition: border-color 0.2s;
            cursor: pointer;
            margin-bottom: 24px;
        }

        .file-drop-area:hover,
        .file-drop-area.dragover {
            border-color: var(--border-focus);
        }

        .fake-btn {
            background: var(--card-bg);
            border: 1px solid var(--border);
            border-radius: 6px;
            padding: 8px 16px;
            font-size: 13px;
            font-weight: 500;
            margin-bottom: 10px;
            pointer-events: none;
            color: var(--text-main);
        }

        .file-msg {
            color: var(--text-muted);
            pointer-events: none;
            font-size: 14px;
        }

        .file-input {
            position: absolute;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            opacity: 0;
            cursor: pointer;
            z-index: 10;
        }

        /* File List */
        .file-list {
            display: flex;
            flex-direction: column;
            gap: 12px;
            margin-bottom: 24px;
        }

        .file-item {
            display: flex;
            align-items: center;
            gap: 16px;
            background: var(--input-bg);
            padding: 14px;
            border-radius: 8px;
            border: 1px solid var(--border);
        }

        .file-preview {
            width: 56px;
            height: 56px;
            border-radius: 6px;
            object-fit: cover;
            background: #e8e5e0;
        }

        .file-info {
            flex: 1;
            min-width: 0;
        }

        .file-name {
            font-size: 13px;
            font-weight: 500;
            margin-bottom: 8px;
            display: block;
            white-space: nowrap;
            overflow: hidden;
            text-overflow: ellipsis;
            width: 100%;
            color: var(--text-main);
        }

        .btn-remove {
            background: none;
            border: none;
            color: var(--text-muted);
            cursor: pointer;
            padding: 8px;
            transition: color 0.2s;
            flex-shrink: 0;
        }

        .btn-remove:hover {
            color: var(--error);
        }

        /* Progress Bar */
        .progress-container {
            width: 100%;
            height: 4px;
            background: var(--border);
            border-radius: 2px;
            margin-bottom: 20px;
            overflow: hidden;
            display: none;
        }

        .progress-bar {
            height: 100%;
            width: 0%;
            background: var(--accent);
            transition: width 0.2s ease;
        }

        /* Submit */
        .btn-submit {
            width: 100%;
            padding: 14px;
            background: var(--primary);
            color: #ffffff;
            border: none;
            border-radius: 8px;
            font-size: 15px;
            font-weight: 500;
            cursor: pointer;
            transition: background 0.2s;
        }

        .btn-submit:hover {
            background: var(--primary-hover);
        }

        .btn-submit:disabled {
            background: var(--border);
            cursor: not-allowed;
            color: var(--text-muted);
        }

        /* Status */
        .status-container {
            margin-top: 24px;
            display: flex;
            flex-direction: column;
            gap: 8px;
        }

        .status-msg {
            padding: 12px;
            border-radius: 6px;
            font-size: 13px;
            display: flex;
            align-items: center;
            gap: 8px;
        }

        .status-msg.success {
            background: #eef4ef;
            color: var(--success);
            border: 1px solid #d3e0d4;
        }

        .status-msg.error {
            background: #f8efec;
            color: var(--error);
            border: 1px solid #e6d4ce;
        }

        /* Mobile Optimization */
        @media (max-width: 600px) {
            .container {
                padding: 24px 20px;
                border-radius: 8px;
            }

            .file-item {
                gap: 12px;
                padding: 12px;
            }

            .file-preview {
                width: 48px;
                height: 48px;
            }

            .batch-controls {
                flex-direction: column;
                align-items: stretch;
            }
        }
    </style>
</head>

<body>

    <div class="container">
        <h1><?= htmlspecialchars(EVENT_NAME) ?></h1>
        <p class="subtitle"><?= htmlspecialchars(EVENT_SUBTITLE) ?></p>

        <!-- Countdown -->
        <div id="countdown" class="countdown-box">Lädt...</div>

        <!-- Batch Controls -->
        <div class="batch-controls">
            <div class="form-group-batch">
                <label>Sammel-Beschreibung</label>
                <input type="text" id="globalDesc" placeholder="Eine Beschreibung für alle...">
            </div>
            <button type="button" class="btn-secondary" id="applyAllBtn">Auf alle anwenden</button>
        </div>

        <form action="" method="POST" enctype="multipart/form-data" id="uploadForm">

            <!-- Drop Area -->
            <div class="file-drop-area" id="dropArea">
                <span class="fake-btn">Dateien wählen</span>
                <span class="file-msg">oder per Drag & Drop (Max. 15MB/Bild)</span>
                <input class="file-input" type="file" name="images[]" id="fileInput" accept="image/*" multiple>
            </div>

            <!-- Dynamic File List -->
            <div class="file-list" id="fileList"></div>

            <!-- Progress Bar -->
            <div class="progress-container" id="progressContainer">
                <div class="progress-bar" id="progressBar"></div>
            </div>

            <button type="submit" class="btn-submit" id="submitBtn">Alles hochladen</button>
        </form>

        <!-- Status Output -->
        <div class="status-container" id="statusContainer"></div>
    </div>

    <script>
        // Configuration from PHP
        const DEADLINE_TIMESTAMP = <?php echo strtotime(UPLOAD_DEADLINE) * 1000; ?>;

        const fileInput = document.getElementById('fileInput');
        const dropArea = document.getElementById('dropArea');
        const fileListEl = document.getElementById('fileList');
        const globalDescInput = document.getElementById('globalDesc');
        const applyAllBtn = document.getElementById('applyAllBtn');
        const uploadForm = document.getElementById('uploadForm');
        const progressBar = document.getElementById('progressBar');
        const progressContainer = document.getElementById('progressContainer');
        const statusContainer = document.getElementById('statusContainer');
        const submitBtn = document.getElementById('submitBtn');
        const countdownEl = document.getElementById('countdown');

        const dataTransfer = new DataTransfer();

        /* --- Countdown Logic --- */
        function updateCountdown() {
            const now = new Date().getTime();
            const distance = DEADLINE_TIMESTAMP - now;

            if (distance < 0) {
                countdownEl.innerHTML = "Upload-Zeitraum abgelaufen.";
                countdownEl.style.color = "var(--error)";
                countdownEl.style.borderColor = "#e6d4ce";
                countdownEl.style.background = "#f8efec";
                disableForm();
                return;
            }

            const days = Math.floor(distance / (1000 * 60 * 60 * 24));
            const hours = Math.floor((distance % (1000 * 60 * 60 * 24)) / (1000 * 60 * 60));
            const minutes = Math.floor((distance % (1000 * 60 * 60)) / (1000 * 60));
            const seconds = Math.floor((distance % (1000 * 60)) / 1000);

            countdownEl.innerHTML = `Noch ${days}t ${hours}h ${minutes}m ${seconds}s bis zum Upload-Schluss`;
        }

        function disableForm() {
            submitBtn.disabled = true;
            submitBtn.innerText = "Upload geschlossen";
            fileInput.disabled = true;
            dropArea.style.pointerEvents = 'none'; // Disable drop area interaction
            dropArea.style.opacity = '0.6'; // Visual cue
            applyAllBtn.disabled = true;
            globalDescInput.disabled = true;
            // Also disable individual description inputs if any are rendered
            Array.from(document.getElementsByName('descriptions[]')).forEach(input => input.disabled = true);
        }

        setInterval(updateCountdown, 1000);
        updateCountdown(); // Initial call to display immediately

        /* --- File Handling --- */
        fileInput.addEventListener('change', (e) => handleFiles(e.target.files));

        dropArea.addEventListener('dragenter', () => dropArea.classList.add('dragover'));
        dropArea.addEventListener('dragleave', () => dropArea.classList.remove('dragover'));
        dropArea.addEventListener('drop', (e) => dropArea.classList.remove('dragover'));

        function handleFiles(files) {
            // Check if form is disabled due to deadline
            if (submitBtn.disabled) {
                alert("Der Upload-Zeitraum ist abgelaufen. Es können keine neuen Dateien hinzugefügt werden.");
                return;
            }

            for (let i = 0; i < files.length; i++) dataTransfer.items.add(files[i]);
            fileInput.files = dataTransfer.files;
            renderFileList();
        }

        function renderFileList() {
            fileListEl.innerHTML = '';
            Array.from(fileInput.files).forEach((file, index) => {
                const item = document.createElement('div');
                item.className = 'file-item';

                const img = document.createElement('img');
                img.className = 'file-preview';
                img.src = URL.createObjectURL(file);
                img.onload = () => URL.revokeObjectURL(img.src);

                const infoDiv = document.createElement('div');
                infoDiv.className = 'file-info';

                const nameSpan = document.createElement('span');
                nameSpan.className = 'file-name';
                nameSpan.textContent = file.name;

                const descInput = document.createElement('input');
                descInput.type = 'text';
                descInput.name = 'descriptions[]';
                descInput.placeholder = 'Beschreibung...';
                descInput.required = true;
                if (submitBtn.disabled) { // If deadline passed, disable new inputs
                    descInput.disabled = true;
                }

                infoDiv.appendChild(nameSpan);
                infoDiv.appendChild(descInput);

                const removeBtn = document.createElement('button');
                removeBtn.type = 'button';
                removeBtn.className = 'btn-remove';
                removeBtn.innerHTML = '<svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>';
                removeBtn.onclick = () => removeFile(index);
                if (submitBtn.disabled) { // If deadline passed, disable remove button
                    removeBtn.disabled = true;
                    removeBtn.style.opacity = '0.5';
                    removeBtn.style.cursor = 'not-allowed';
                }

                item.appendChild(img);
                item.appendChild(infoDiv);
                item.appendChild(removeBtn);

                fileListEl.appendChild(item);
            });
        }

        function removeFile(index) {
            const dt = new DataTransfer();
            const files = fileInput.files;
            const currentDescs = Array.from(document.getElementsByName('descriptions[]')).map(i => i.value);

            for (let i = 0; i < files.length; i++) {
                if (i !== index) dt.items.add(files[i]);
            }

            fileInput.files = dt.files;
            renderFileList();

            const newInputs = document.getElementsByName('descriptions[]');
            let offset = 0;
            for (let i = 0; i < currentDescs.length; i++) {
                if (i === index) {
                    offset = 1;
                    continue;
                }
                if (newInputs[i - offset]) newInputs[i - offset].value = currentDescs[i];
            }

            dataTransfer.items.clear();
            for (let i = 0; i < dt.files.length; i++) dataTransfer.items.add(dt.files[i]);
        }

        applyAllBtn.addEventListener('click', () => {
            const val = globalDescInput.value;
            if (!val) return;
            const inputs = document.getElementsByName('descriptions[]');
            for (let input of inputs) input.value = val;
        });

        /* --- AJAX Upload --- */
        uploadForm.addEventListener('submit', (e) => {
            e.preventDefault();

            // Client-side deadline check (redundant but good UX)
            if (new Date().getTime() > DEADLINE_TIMESTAMP) {
                alert("Der Upload-Zeitraum ist abgelaufen. Bitte aktualisieren Sie die Seite.");
                disableForm();
                return;
            }

            // Basic validation
            if (fileInput.files.length === 0) {
                alert("Bitte wähle mindestens eine Datei aus.");
                return;
            }

            // Validate all description fields are filled
            const descriptionInputs = document.getElementsByName('descriptions[]');
            for (let input of descriptionInputs) {
                if (!input.value.trim()) {
                    alert("Bitte füllen Sie alle Beschreibungsfelder aus.");
                    input.focus();
                    return;
                }
            }

            const formData = new FormData(uploadForm);
            const xhr = new XMLHttpRequest();

            // UI Reset
            statusContainer.innerHTML = ''; // Clear previous messages
            progressContainer.style.display = 'block';
            progressBar.style.width = '0%';
            submitBtn.disabled = true;
            submitBtn.innerText = 'Wird hochgeladen...';
            fileInput.disabled = true; // Disable file input during upload
            dropArea.style.pointerEvents = 'none';
            applyAllBtn.disabled = true;
            globalDescInput.disabled = true;
            Array.from(document.getElementsByName('descriptions[]')).forEach(input => input.disabled = true);
            Array.from(document.querySelectorAll('.btn-remove')).forEach(btn => btn.disabled = true);


            // Progress Listener
            xhr.upload.addEventListener('progress', (event) => {
                if (event.lengthComputable) {
                    const percent = (event.loaded / event.total) * 100;
                    progressBar.style.width = percent + '%';
                }
            });

            // Load Listener
            xhr.addEventListener('load', () => {
                submitBtn.disabled = false;
                submitBtn.innerText = 'Alles hochladen';
                progressContainer.style.display = 'none';
                fileInput.disabled = false; // Re-enable file input
                dropArea.style.pointerEvents = 'auto';
                applyAllBtn.disabled = false;
                globalDescInput.disabled = false;
                Array.from(document.getElementsByName('descriptions[]')).forEach(input => input.disabled = false);
                Array.from(document.querySelectorAll('.btn-remove')).forEach(btn => btn.disabled = false);


                try {
                    const json = JSON.parse(xhr.responseText);

                    if (json.messages && Array.isArray(json.messages)) {
                        json.messages.forEach(msg => {
                            const div = document.createElement('div');
                            div.className = `status-msg ${msg.type}`;
                            div.innerHTML = msg.text;
                            statusContainer.appendChild(div);
                        });
                    }

                    // If all uploads were successful, clear the file list
                    const allSuccess = json.messages.every(msg => msg.type === 'success');
                    if (allSuccess && json.messages.length > 0) {
                        dataTransfer.items.clear();
                        fileInput.files = dataTransfer.files;
                        renderFileList(); // Clear the displayed list
                    }

                } catch (err) {
                    console.error(err);
                    const div = document.createElement('div');
                    div.className = 'status-msg error';
                    div.textContent = 'Fehler beim Verarbeiten der Antwort: ' + xhr.responseText;
                    statusContainer.appendChild(div);
                }
            });

            // Error Listener
            xhr.addEventListener('error', () => {
                submitBtn.disabled = false;
                submitBtn.innerText = 'Alles hochladen';
                progressContainer.style.display = 'none';
                fileInput.disabled = false; // Re-enable file input
                dropArea.style.pointerEvents = 'auto';
                applyAllBtn.disabled = false;
                globalDescInput.disabled = false;
                Array.from(document.getElementsByName('descriptions[]')).forEach(input => input.disabled = false);
                Array.from(document.querySelectorAll('.btn-remove')).forEach(btn => btn.disabled = false);

                const div = document.createElement('div');
                div.className = 'status-msg error';
                div.textContent = 'Netzwerkfehler beim Upload.';
                statusContainer.appendChild(div);
            });

            xhr.open('POST', '', true);
            xhr.send(formData);
        });
    </script>

</body>

</html>