---
import DefaultLayout from '../layouts/DefaultLayout.astro';

const WORKER_URL = import.meta.env.PUBLIC_WORKER_URL;
const UPLOAD_SECRET = import.meta.env.PUBLIC_UPLOAD_SECRET;
---

<DefaultLayout>
  <section>
    <h4>Upload</h4>

    <div id="drop-zone" class="drop-zone">
      <p class="drop-hint">Drag & drop files here or</p>
      <label for="file-input" class="file-label">Choose files</label>
      <input id="file-input" type="file" accept="video/*,image/*" multiple class="file-input" />
    </div>

    <div id="preview-grid" class="preview-grid"></div>

    <button id="upload-btn" class="upload-btn" disabled>Upload all</button>

    <div id="status" class="status"></div>
  </section>
</DefaultLayout>

<script define:vars={{ WORKER_URL, UPLOAD_SECRET }}>
  const dropZone = document.getElementById('drop-zone');
  const fileInput = document.getElementById('file-input');
  const previewGrid = document.getElementById('preview-grid');
  const uploadBtn = document.getElementById('upload-btn');
  const statusEl = document.getElementById('status');

  let selectedFiles = [];

  function setStatus(msg, type) {
    statusEl.textContent = msg;
    statusEl.className = 'status ' + (type || '');
  }

  function addFiles(incoming) {
    const valid = Array.from(incoming).filter(f =>
      f.type.startsWith('video/') || f.type.startsWith('image/')
    );

    if (valid.length !== incoming.length) {
      setStatus('Some files were skipped — only videos and images are accepted.', 'error');
    } else {
      setStatus('', '');
    }

    for (const file of valid) {
      if (selectedFiles.find(f => f.name === file.name && f.size === file.size)) continue;
      selectedFiles.push(file);
      renderPreview(file);
    }

    uploadBtn.disabled = selectedFiles.length === 0;
  }

  function renderPreview(file) {
    const objectUrl = URL.createObjectURL(file);
    const card = document.createElement('div');
    card.className = 'preview-card';
    card.dataset.name = file.name;

    let media;
    if (file.type.startsWith('video/')) {
      media = document.createElement('video');
      media.src = objectUrl;
      media.controls = true;
      media.muted = true;
      media.playsInline = true;
    } else {
      media = document.createElement('img');
      media.src = objectUrl;
      media.alt = file.name;
    }

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

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

    const size = document.createElement('span');
    size.className = 'preview-size';
    size.textContent = formatSize(file.size);

    const progress = document.createElement('div');
    progress.className = 'preview-progress hidden';
    progress.innerHTML = `<div class="preview-bar"></div><span class="preview-pct">0%</span>`;

    const removeBtn = document.createElement('button');
    removeBtn.className = 'preview-remove';
    removeBtn.textContent = '×';
    removeBtn.addEventListener('click', () => {
      selectedFiles = selectedFiles.filter(f => f !== file);
      URL.revokeObjectURL(objectUrl);
      card.remove();
      uploadBtn.disabled = selectedFiles.length === 0;
    });

    info.append(name, size, progress);
    card.append(media, info, removeBtn);
    previewGrid.appendChild(card);
  }

  function formatSize(bytes) {
    if (bytes < 1024) return bytes + ' B';
    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
    return (bytes / (1024 * 1024)).toFixed(1) + ' MB';
  }

  function setCardProgress(filename, pct, done, error) {
    const card = previewGrid.querySelector(`[data-name="${CSS.escape(filename)}"]`);
    if (!card) return;
    const wrap = card.querySelector('.preview-progress');
    const bar = card.querySelector('.preview-bar');
    const pctEl = card.querySelector('.preview-pct');
    wrap.classList.remove('hidden');
    bar.style.width = pct + '%';
    pctEl.textContent = pct + '%';
    if (done) card.classList.add('done');
    if (error) card.classList.add('errored');
  }

  fileInput.addEventListener('change', (e) => addFiles(e.target.files));

  dropZone.addEventListener('dragover', (e) => {
    e.preventDefault();
    dropZone.classList.add('drag-over');
  });
  dropZone.addEventListener('dragleave', () => dropZone.classList.remove('drag-over'));
  dropZone.addEventListener('drop', (e) => {
    e.preventDefault();
    dropZone.classList.remove('drag-over');
    addFiles(e.dataTransfer.files);
  });

  uploadBtn.addEventListener('click', async () => {
    if (selectedFiles.length === 0) return;
    uploadBtn.disabled = true;
    setStatus(`Uploading ${selectedFiles.length} file(s)…`, 'info');

    const results = await Promise.allSettled(selectedFiles.map(uploadFile));

    const failed = results.filter(r => r.status === 'rejected').length;
    if (failed === 0) {
      setStatus(`All ${selectedFiles.length} file(s) uploaded successfully.`, 'success');
    } else {
      setStatus(`${failed} file(s) failed. Check the previews.`, 'error');
    }

    uploadBtn.disabled = false;
  });

  async function uploadFile(file) {
    const res = await fetch(
      `${WORKER_URL}/presign?filename=${encodeURIComponent(file.name)}`,
      { headers: { Authorization: `Bearer ${UPLOAD_SECRET}` } }
    );

    if (!res.ok) {
      const body = await res.json().catch(() => ({}));
      setCardProgress(file.name, 0, false, true);
      throw new Error(body.error || `Worker responded ${res.status}`);
    }

    const { url } = await res.json();

    await new Promise((resolve, reject) => {
      const xhr = new XMLHttpRequest();
      xhr.open('PUT', url);
      xhr.setRequestHeader('Content-Type', file.type);

      xhr.upload.addEventListener('progress', (e) => {
        if (e.lengthComputable) {
          setCardProgress(file.name, Math.round((e.loaded / e.total) * 100), false, false);
        }
      });

      xhr.addEventListener('load', () => {
        if (xhr.status >= 200 && xhr.status < 300) {
          setCardProgress(file.name, 100, true, false);
          resolve();
        } else {
          setCardProgress(file.name, 0, false, true);
          reject(new Error(`R2 upload failed: ${xhr.status}`));
        }
      });

      xhr.addEventListener('error', () => {
        setCardProgress(file.name, 0, false, true);
        reject(new Error('Network error'));
      });

      xhr.send(file);
    });
  }
</script>

<style>
  section {
    color: #eeeeee;
  }

  h4 {
    font-size: 1.15rem;
    margin: 0 0 1.2em 0;
    color: #eeeeee;
  }

  .drop-zone {
    border: 2px dashed #444;
    border-radius: 6px;
    padding: 2em 1.5em;
    text-align: center;
    cursor: pointer;
    transition: border-color 0.2s, background 0.2s;
    margin-bottom: 1em;
  }

  .drop-zone.drag-over {
    border-color: #4ecca3;
    background: rgba(78, 204, 163, 0.05);
  }

  .drop-hint {
    margin: 0 0 0.6em 0;
    color: #aaa;
    font-size: 0.95rem;
  }

  .file-input {
    display: none;
  }

  .file-label {
    display: inline-block;
    padding: 0.4em 1em;
    background: transparent;
    border: 1px solid #4ecca3;
    color: #4ecca3;
    border-radius: 4px;
    cursor: pointer;
    font-size: 0.9rem;
    transition: background 0.2s, color 0.2s;
  }

  .file-label:hover {
    background: #4ecca3;
    color: #1a1a2e;
  }

  /* Preview grid */

  .preview-grid {
    display: grid;
    grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
    gap: 1em;
    margin-bottom: 1em;
  }

  .preview-card {
    position: relative;
    background: #1e1e2e;
    border: 1px solid #333;
    border-radius: 6px;
    overflow: hidden;
    display: flex;
    flex-direction: column;
    transition: border-color 0.2s;
  }

  .preview-card.done {
    border-color: #4ecca3;
  }

  .preview-card.errored {
    border-color: #e05c5c;
  }

  .preview-card video,
  .preview-card img {
    width: 100%;
    aspect-ratio: 16 / 9;
    object-fit: cover;
    display: block;
    background: #111;
  }

  .preview-info {
    padding: 0.5em 0.6em;
    display: flex;
    flex-direction: column;
    gap: 0.2em;
  }

  .preview-name {
    font-size: 0.75rem;
    color: #ccc;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
  }

  .preview-size {
    font-size: 0.7rem;
    color: #666;
  }

  .preview-progress {
    display: flex;
    align-items: center;
    gap: 0.4em;
    margin-top: 0.3em;
  }

  .preview-progress.hidden {
    display: none;
  }

  .preview-bar {
    flex: 1;
    height: 4px;
    background: #4ecca3;
    border-radius: 2px;
    transition: width 0.2s;
  }

  .preview-pct {
    font-size: 0.65rem;
    color: #aaa;
    min-width: 3ch;
  }

  .preview-remove {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 22px;
    height: 22px;
    border-radius: 50%;
    background: rgba(0, 0, 0, 0.6);
    border: none;
    color: #fff;
    font-size: 1rem;
    line-height: 1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.15s;
  }

  .preview-card:hover .preview-remove {
    opacity: 1;
  }

  /* Upload button */

  .upload-btn {
    display: block;
    padding: 0.5em 1.6em;
    background: #4ecca3;
    color: #1a1a2e;
    border: none;
    border-radius: 4px;
    font-size: 1rem;
    font-weight: 600;
    cursor: pointer;
    transition: opacity 0.2s;
    margin-bottom: 1em;
  }

  .upload-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
  }

  .upload-btn:not(:disabled):hover {
    opacity: 0.85;
  }

  .status {
    font-size: 0.9rem;
    min-height: 1.2em;
  }

  .status.info    { color: #aaa; }
  .status.success { color: #4ecca3; }
  .status.error   { color: #e05c5c; }
</style>
