// ===========================
// TRANSLATIONS
// ===========================
const T = {
  fi: {
    tagline: 'Jaa asioita joista tykkäät — reseptejä, vinkkejä, ideoita',
    nav_posts: 'Julkaisut', nav_about: 'Tietoa', nav_contact: 'Yhteystiedot', nav_admin: 'Hallinta',
    hero_title: 'Tervetuloa tykkää.fi:hin!',
    hero_desc: 'Jaa ja löydä reseptejä, neulomisvinkkejä, elämänohjeita — ja kaikkea muuta mitä rakastat.',
    hero_btn: 'Selaa julkaisuja',
    search_ph: 'Hae julkaisuja...',
    filter_all: 'Kaikki',
    view_btn: 'Lue lisää',
    no_results: 'Julkaisuja ei löydy. Kokeile eri hakusanaa!',
    about_title: 'Mikä tykkää.fi?',
    about_text: 'tykkää.fi on avoin yhteisö, jonne kuka tahansa voi tulla jakamaan asioita joista tykkää. Reseptejä, neulomisohjeita, käsityöideoita tai ihan mitä muuta kivaa — tärkeintä on jakamisen ilo. Lisää oma julkaisusi yläkulman napista!',
    contact_title: 'Ota yhteyttä',
    contact_desc: 'Kysyttävää tai ehdotuksia? Lähetä meille viestiä!',
    name_ph: 'Nimesi', email_ph: 'Sähköpostisi', msg_ph: 'Viestisi...',
    send_btn: 'Lähetä viesti', msg_sent: 'Viesti lähetetty! ✓', msg_error: 'Virhe lähetyksessä. Yritä uudelleen.',
    footer: 'Avoin yhteisö kaikille',
    modal_by: 'Kirjoittanut',
    modal_ingredients: 'Ainekset', modal_steps: 'Ohjeet',
    modal_comments: 'Kommentit',
    no_comments: 'Ei kommentteja vielä. Ole ensimmäinen!',
    comment_name_ph: 'Nimesi', comment_ph: 'Kirjoita kommentti...',
    comment_btn: 'Lähetä kommentti',
    like_btn: '❤️ Tykkää', liked_btn: '❤️ Tykätty',
    no_ingredients: 'Aineksia ei lisätty.', no_steps: 'Ohjeita ei lisätty.',
    login_btn: 'Kirjaudu', logout_btn: 'Kirjaudu ulos', register_btn: 'Rekisteröidy',
    login_title: 'Kirjaudu sisään', register_title: 'Luo tili',
    nickname_ph: 'Nimimerkki', password_ph: 'Salasana', email_ph_reg: 'Sähköposti (vapaaehtoinen)',
    login_submit: 'Kirjaudu', register_submit: 'Luo tili',
    switch_to_login: 'Onko sinulla jo tili? Kirjaudu sisään',
    switch_to_register: 'Eikö sinulla ole tiliä? Rekisteröidy',
    logged_in_as: 'Kirjautunut:', my_likes_btn: '❤️ Tykkäämäni',
    auth_fields_required: 'Täytä nimimerkki ja salasana.',
  },
  en: {
    tagline: 'Share things you love — recipes, tips, ideas',
    nav_posts: 'Posts', nav_about: 'About', nav_contact: 'Contact', nav_admin: 'Admin',
    hero_title: 'Welcome to tykkää.fi!',
    hero_desc: 'Share and discover recipes, knitting tips, life advice — and everything else you love.',
    hero_btn: 'Browse Posts',
    search_ph: 'Search posts...',
    filter_all: 'All',
    view_btn: 'Read more',
    no_results: 'No posts found. Try a different search!',
    about_title: 'What is tykkää.fi?',
    about_text: 'tykkää.fi is an open community where anyone can share things they love. Recipes, knitting patterns, craft ideas or anything fun — the joy of sharing is what matters. Add your own post using the button in the top corner!',
    contact_title: 'Get in Touch',
    contact_desc: 'Questions or suggestions? Send us a message!',
    name_ph: 'Your name', email_ph: 'Your email', msg_ph: 'Your message...',
    send_btn: 'Send Message', msg_sent: 'Message Sent! ✓', msg_error: 'Error sending. Please try again.',
    footer: 'Open community for everyone',
    modal_by: 'By',
    modal_ingredients: 'Ingredients', modal_steps: 'Instructions',
    modal_comments: 'Comments',
    no_comments: 'No comments yet. Be the first!',
    comment_name_ph: 'Your name', comment_ph: 'Write a comment...',
    comment_btn: 'Post Comment',
    like_btn: '❤️ Like', liked_btn: '❤️ Liked',
    no_ingredients: 'No ingredients listed.', no_steps: 'No instructions listed.',
    login_btn: 'Log in', logout_btn: 'Log out', register_btn: 'Register',
    login_title: 'Log In', register_title: 'Create Account',
    nickname_ph: 'Nickname', password_ph: 'Password', email_ph_reg: 'Email (optional)',
    login_submit: 'Log In', register_submit: 'Create Account',
    switch_to_login: 'Already have an account? Log in',
    switch_to_register: "Don't have an account? Register",
    logged_in_as: 'Logged in:', my_likes_btn: '❤️ My Likes',
    auth_fields_required: 'Nickname and password are required.',
  }
};

const lang = 'fi';
function t(key) { return (T[lang] && T[lang][key]) ? T[lang][key] : key; }

function applyTranslations() {
  document.documentElement.lang = lang;
  document.querySelectorAll('[data-i18n]').forEach(el => { el.textContent = t(el.dataset.i18n); });
  document.querySelectorAll('[data-i18n-ph]').forEach(el => { el.placeholder = t(el.dataset.i18nPh); });
}

// ===========================
// HELPERS
// ===========================
function sortSubcategories(subs) {
  return [...subs].sort((a, b) => {
    const aM = a.fi.toLowerCase() === 'muut' ? 1 : 0;
    const bM = b.fi.toLowerCase() === 'muut' ? 1 : 0;
    if (aM !== bM) return aM - bM;
    return a.fi.localeCompare(b.fi, 'fi');
  });
}

// ===========================
// API
// ===========================
async function apiGet(action, params = {}) {
  const qs = new URLSearchParams({ action, ...params }).toString();
  const res = await fetch(`api.php?${qs}`);
  return res.json();
}

async function apiPost(action, body = {}) {
  const res = await fetch(`api.php?action=${action}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
  });
  return res.json();
}

// ===========================
// APP STATE
// ===========================
const APP = {
  posts: [],
  categories: [],
  likes: {},
  userLikes: [],
  user: null,
  showOnlyLiked: false,
};

// ===========================
// CATEGORIES
// ===========================
function getCategoryLabel(catId) {
  const cat = APP.categories.find(c => c.id === catId);
  return cat ? cat.fi : catId;
}

function countPostsInCategory(catId) {
  return APP.posts.filter(p => p.category === catId).length;
}

function countPostsInSubcategory(catId, subId) {
  return APP.posts.filter(p => {
    if (p.category !== catId) return false;
    const subs = Array.isArray(p.subcategory) ? p.subcategory : [p.subcategory].filter(Boolean);
    return subs.includes(subId);
  }).length;
}

function renderCategoryFilters() {
  const cats = APP.categories.filter(c => countPostsInCategory(c.id) > 0);
  const container = document.getElementById('categoryFilters');
  if (!container) return;
  container.innerHTML =
    `<button class="filter-btn ${currentFilter === 'all' ? 'active' : ''}" onclick="setFilter('all',this)">${t('filter_all')}</button>` +
    cats.map(c => `<button class="filter-btn ${currentFilter === c.id ? 'active' : ''}" onclick="setFilter('${c.id}',this)">${c.emoji ? c.emoji + ' ' : ''}${c.fi}</button>`).join('');
}

// ===========================
// LIKES
// ===========================
async function toggleLike(id) {
  const data = await apiPost('toggle_like', { postId: id });
  if (data.error) return;

  const liked = data.liked;
  const count = data.count;

  // Update in-memory state
  APP.likes[id] = count;
  if (liked) {
    if (!APP.userLikes.includes(id)) APP.userLikes.push(id);
  } else {
    APP.userLikes = APP.userLikes.filter(x => x !== id);
  }
  // Persist to localStorage so likes survive session expiry
  saveLocalLikes(APP.userLikes);

  // Update all like buttons for this post (card + modal)
  document.querySelectorAll(`[data-like-id="${id}"]`).forEach(btn => {
    btn.textContent = liked ? t('liked_btn') : t('like_btn');
    btn.classList.toggle('liked', liked);
  });
  document.querySelectorAll(`[data-like-count="${id}"]`).forEach(el => {
    el.textContent = count;
  });
  if (APP.showOnlyLiked) filterPosts();
}

// ===========================
// COMMENTS + SPAM PROTECTION
// ===========================
let captchaAnswer = 0;
function generateCaptcha() {
  const a = Math.floor(Math.random() * 9) + 1;
  const b = Math.floor(Math.random() * 9) + 1;
  captchaAnswer = a + b;
  return `Laske: ${a} + ${b} = ?`;
}

function renderCommentsList(comments) {
  if (!comments || !comments.length) return `<p class="empty-note">${t('no_comments')}</p>`;
  return comments.map(c => `
    <div class="comment">
      <div class="comment-header"><strong>${c.name}</strong><span>${c.time}</span></div>
      <p>${c.text}</p>
    </div>
  `).join('');
}

// ===========================
// RENDER CARDS
// ===========================
function renderCards() {
  const grid = document.getElementById('postGrid');
  if (!grid) return;

  grid.innerHTML = APP.posts.map(p => {
    const liked = APP.userLikes.includes(p.id);
    const likeCount = APP.likes[p.id] || 0;
    const metaRow = p.time ? `<div class="card-meta"><span>⏱ ${p.time}</span><span>👤 ${p.servings}</span></div>` : '';
    const imgSrc = p.images?.[0];
    const cardImgHTML = imgSrc
      ? `<div class="card-img card-has-photo"><img src="${imgSrc}" alt="${p.title}" /></div>`
      : `<div class="card-img">${p.emoji}</div>`;
    return `
      <article class="recipe-card" data-category="${p.category}" data-subcategory="${Array.isArray(p.subcategory) ? p.subcategory.join(',') : (p.subcategory || '')}" onclick="openPost('${p.id}')">
        ${cardImgHTML}
        <div class="card-body">
          <span class="category-tag">${getCategoryLabel(p.category)}</span>
          <h3>${p.title}</h3>
          ${p.author ? `<p class="card-author">✍️ ${p.submittedBy?.validated ? `<strong>${p.author}</strong> <span class="validated-badge">✔ Kirjautunut</span>` : `${p.author}${p.submittedBy?.guestCode ? ` <span class="guest-badge">#${p.submittedBy.guestCode}</span>` : ''}`}</p>` : ''}
          <p>${p.desc || ''}</p>
          ${metaRow}
          <div class="card-actions">
            <button class="btn-outline" onclick="event.stopPropagation(); openPost('${p.id}')">${t('view_btn')}</button>
            <div class="like-row" onclick="event.stopPropagation()">
              <button class="like-btn ${liked ? 'liked' : ''}" data-like-id="${p.id}" onclick="toggleLike('${p.id}')">${liked ? t('liked_btn') : t('like_btn')}</button>
              <span class="like-count" data-like-count="${p.id}">${likeCount}</span>
            </div>
          </div>
        </div>
      </article>
    `;
  }).join('');
}

// ===========================
// FILTER & SEARCH
// ===========================
let currentFilter    = 'all';
let currentSubFilter = 'all';

function setFilter(category, btn) {
  currentFilter    = category;
  currentSubFilter = 'all';
  document.querySelectorAll('.filter-btn').forEach(b => b.classList.remove('active'));
  btn.classList.add('active');
  renderSubFilters();
  filterPosts();
}

function setSubFilter(sub, btn) {
  currentSubFilter = sub;
  document.querySelectorAll('.sub-filter-btn').forEach(b => b.classList.remove('active'));
  btn.classList.add('active');
  filterPosts();
}

function renderSubFilters() {
  const container = document.getElementById('subCategoryFilters');
  if (!container) return;
  if (currentFilter === 'all') { container.innerHTML = ''; return; }
  const cat = APP.categories.find(c => c.id === currentFilter);
  const subs = sortSubcategories((cat?.subcategories || []).filter(s => countPostsInSubcategory(currentFilter, s.id) > 0));
  if (!subs.length) { container.innerHTML = ''; return; }
  container.innerHTML =
    `<button class="sub-filter-btn ${currentSubFilter === 'all' ? 'active' : ''}" onclick="setSubFilter('all',this)">Kaikki</button>` +
    subs.map(s => `<button class="sub-filter-btn ${currentSubFilter === s.id ? 'active' : ''}" onclick="setSubFilter('${s.id}',this)">${s.fi}</button>`).join('');
}

function filterPosts() {
  const query = (document.getElementById('search')?.value || '').toLowerCase();
  const cards = document.querySelectorAll('.recipe-card');
  let visible = 0;
  cards.forEach(card => {
    const matchesCat  = currentFilter === 'all' || card.dataset.category === currentFilter;
    const postSubs    = (card.dataset.subcategory || '').split(',').filter(Boolean);
    const matchesSub  = currentSubFilter === 'all' || postSubs.includes(currentSubFilter);
    const title  = (card.querySelector('h3')?.textContent || '').toLowerCase();
    const desc   = (card.querySelector('p:not(.card-author)')?.textContent || '').toLowerCase();
    const subLbl = (card.dataset.subcategory || '').toLowerCase();
    const matchesSearch = !query || title.includes(query) || desc.includes(query) || subLbl.includes(query);
    const postId = card.querySelector('[data-like-id]')?.dataset.likeId || '';
    const matchesLikes = !APP.showOnlyLiked || APP.userLikes.includes(postId);
    const show = matchesCat && matchesSub && matchesSearch && matchesLikes;
    card.style.display = show ? '' : 'none';
    if (show) visible++;
  });
  const noRes = document.getElementById('noResults');
  if (noRes) noRes.style.display = visible === 0 ? 'block' : 'none';
}

// ===========================
// MODAL
// ===========================
async function openPost(id) {
  const p = APP.posts.find(x => x.id === id);
  if (!p) return;

  const liked = APP.userLikes.includes(p.id);
  const likeCount = APP.likes[p.id] || 0;

  // Load comments from server
  const commData = await apiGet('comments', { postId: id });
  const comments = commData.comments || [];

  let bodyHTML = '';
  if (p.type === 'recipe') {
    const ings = p.ingredients?.length
      ? `<ul>${p.ingredients.map(i => `<li>${i}</li>`).join('')}</ul>`
      : `<p class="empty-note">${t('no_ingredients')}</p>`;
    const stps = p.steps?.length
      ? `<ol>${p.steps.map(s => `<li>${s}</li>`).join('')}</ol>`
      : `<p class="empty-note">${t('no_steps')}</p>`;
    const copyBtn = p.ingredients?.length
      ? `<button class="copy-list-btn" onclick="copyIngredients('${p.id}')" style="margin-left:10px;padding:4px 12px;font-size:0.82rem;border:1px solid #ccc;background:#fff;border-radius:20px;cursor:pointer;">📋 Kopioi ostoslista</button>`
      : '';
    bodyHTML = `<div style="display:flex;align-items:center;flex-wrap:wrap;gap:6px;margin-bottom:2px"><h3 style="margin:0">${t('modal_ingredients')}</h3>${copyBtn}</div>${ings}<h3>${t('modal_steps')}</h3>${stps}`;
  } else {
    bodyHTML = `<div class="post-body">${p.body || p.desc}</div>`;
  }

  const galleryHTML = p.images?.length
    ? `<div class="img-gallery">${p.images.map(src => `<img src="${src}" alt="${p.title}" onclick="openLightbox(this.src)" />`).join('')}</div>`
    : '';

  document.getElementById('modalContent').innerHTML = `
    ${p.images?.length ? '' : `<span class="modal-emoji">${p.emoji}</span>`}
    ${galleryHTML}
    <h2>${p.title}</h2>
    <p class="modal-meta">
      📂 ${getCategoryLabel(p.category)}
      ${p.time ? `&nbsp;|&nbsp; ⏱ ${p.time} &nbsp;|&nbsp; 👤 ${p.servings}` : ''}
      ${p.author ? `&nbsp;|&nbsp; ✍️ ${t('modal_by')} ${p.submittedBy?.validated ? `<strong>${p.author}</strong> <span class="validated-badge">✔ Kirjautunut</span>` : `${p.author}${p.submittedBy?.guestCode ? ` <span class="guest-badge">#${p.submittedBy.guestCode}</span>` : ''}`}` : ''}
    </p>
    <div class="modal-like-row">
      <button class="like-btn ${liked ? 'liked' : ''}" data-like-id="${p.id}" onclick="toggleLike('${p.id}')">${liked ? t('liked_btn') : t('like_btn')}</button>
      <span class="like-count" data-like-count="${p.id}">${likeCount}</span>
    </div>
    ${bodyHTML}
    <div class="comments-section">
      <h3 id="comments-heading-${p.id}">${t('modal_comments')} (${comments.length})</h3>
      <div id="comments-list-${p.id}">${renderCommentsList(comments)}</div>
      <form class="comment-form" onsubmit="submitComment(event,'${p.id}')">
        <input type="text" placeholder="${t('comment_name_ph')}" required maxlength="50" />
        <textarea placeholder="${t('comment_ph')}" rows="3" required maxlength="500"></textarea>
        <!-- honeypot: bots fill this, humans don't see it -->
        <input type="text" name="website" tabindex="-1" autocomplete="off" style="display:none" />
        <div class="captcha-row">
          <label class="captcha-label" id="captcha-question"></label>
          <input type="number" id="captcha-input" placeholder="Vastaus" required min="0" max="99" style="width:100px" />
        </div>
        <button type="submit" class="btn-outline">${t('comment_btn')}</button>
      </form>
    </div>
  `;

  document.getElementById('modalOverlay').classList.add('open');
  document.body.style.overflow = 'hidden';

  const qEl = document.getElementById('captcha-question');
  if (qEl) qEl.textContent = generateCaptcha();
}

async function submitComment(e, postId) {
  e.preventDefault();

  // Honeypot check
  if (e.target.querySelector('[name="website"]').value) return;

  const name = e.target.querySelector('input[type="text"]').value.trim();
  const text = e.target.querySelector('textarea').value.trim();
  if (!name || !text) return;

  // CAPTCHA check
  const captchaInput = parseInt(e.target.querySelector('#captcha-input').value, 10);
  if (captchaInput !== captchaAnswer) {
    const qEl = document.getElementById('captcha-question');
    if (qEl) {
      qEl.style.color = '#c04040';
      qEl.textContent = 'Väärä vastaus! ' + generateCaptcha();
      setTimeout(() => { qEl.style.color = ''; }, 2000);
    }
    e.target.querySelector('#captcha-input').value = '';
    return;
  }

  const btn = e.target.querySelector('button[type="submit"]');
  btn.disabled = true;
  btn.textContent = '...';

  const data = await apiPost('add_comment', { postId, name, text });

  btn.disabled = false;
  btn.textContent = t('comment_btn');

  if (data.error) {
    const qEl = document.getElementById('captcha-question');
    if (qEl) { qEl.style.color = '#c04040'; qEl.textContent = data.error; }
    return;
  }

  e.target.reset();
  const qEl = document.getElementById('captcha-question');
  if (qEl) qEl.textContent = generateCaptcha();

  // Refresh comments
  const commData = await apiGet('comments', { postId });
  const comments = commData.comments || [];
  const listEl = document.getElementById(`comments-list-${postId}`);
  const headEl = document.getElementById(`comments-heading-${postId}`);
  if (listEl) listEl.innerHTML = renderCommentsList(comments);
  if (headEl) headEl.textContent = `${t('modal_comments')} (${comments.length})`;
}

function closeModal() {
  document.getElementById('modalOverlay').classList.remove('open');
  document.body.style.overflow = '';
}

// ===========================
// LIGHTBOX
// ===========================
function openLightbox(src) {
  document.getElementById('lightboxImg').src = src;
  document.getElementById('lightboxOverlay').classList.add('open');
}
function closeLightbox() {
  document.getElementById('lightboxOverlay').classList.remove('open');
  document.getElementById('lightboxImg').src = '';
}
document.addEventListener('keydown', e => {
  if (e.key === 'Escape') closeLightbox();
});

document.addEventListener('keydown', e => { if (e.key === 'Escape') closeModal(); });

// ===========================
// PUBLIC SUBMISSION
// ===========================
let submitCaptchaAnswer = 0;
let submitType = 'recipe';

function generateSubmitCaptcha() {
  const a = Math.floor(Math.random() * 9) + 1;
  const b = Math.floor(Math.random() * 9) + 1;
  submitCaptchaAnswer = a + b;
  const qEl = document.getElementById('sub-captcha-question');
  if (qEl) qEl.textContent = `Laske: ${a} + ${b} = ?`;
}

function setSubmitType(type) {
  submitType = type;
  document.getElementById('sub-recipeFields').style.display = type === 'recipe' ? '' : 'none';
  document.getElementById('sub-postFields').style.display  = type === 'post'   ? '' : 'none';
}

function updateSubcategoryPicker() {
  const catId = document.getElementById('sub-category').value;
  const cat = APP.categories.find(c => c.id === catId);
  const subs = sortSubcategories(cat?.subcategories || []);
  const group = document.getElementById('sub-subcategory-group');
  const sel = document.getElementById('sub-subcategory');
  if (!subs.length) {
    group.style.display = 'none';
    sel.innerHTML = '';
  } else {
    sel.innerHTML = `<option value="">— Valitse alikategoria —</option>` +
      subs.map(s => `<option value="${s.id}">${s.fi}</option>`).join('');
    group.style.display = '';
  }
  // Näytä reseptikentät jos kategoria on Reseptit, muuten julkaisukentät
  setSubmitType(catId === 'recipes' ? 'recipe' : 'post');
}

function openSubmitModal() {
  const cats = APP.categories;
  const sel = document.getElementById('sub-category');
  sel.innerHTML = cats.map(c => `<option value="${c.id}">${c.emoji || ''} ${c.fi}</option>`).join('');
  updateSubcategoryPicker(); // asettaa myös oikean tyypin kategorian mukaan
  document.getElementById('submitOverlay').classList.add('open');
  document.body.style.overflow = 'hidden';
  generateSubmitCaptcha();
  if (APP.user) {
    const authorField = document.getElementById('sub-author');
    if (authorField && !authorField.value) authorField.value = APP.user.nickname;
  }
}

function closeSubmitModal() {
  document.getElementById('submitOverlay').classList.remove('open');
  document.body.style.overflow = '';
}

async function resizeImage(file, maxPx = 1920, quality = 0.85) {
  // Älä muuta GIF:ejä (animaatio menisi rikki)
  if (file.type === 'image/gif') return file;
  return new Promise(resolve => {
    const img = new Image();
    const url = URL.createObjectURL(file);
    img.onload = () => {
      URL.revokeObjectURL(url);
      const ratio = Math.min(maxPx / img.naturalWidth, maxPx / img.naturalHeight, 1);
      // Jos kuva on jo tarpeeksi pieni, palauta sellaisenaan
      if (ratio === 1 && file.size < 1.5 * 1024 * 1024) { resolve(file); return; }
      const canvas = document.createElement('canvas');
      canvas.width  = Math.round(img.naturalWidth  * ratio);
      canvas.height = Math.round(img.naturalHeight * ratio);
      canvas.getContext('2d').drawImage(img, 0, 0, canvas.width, canvas.height);
      canvas.toBlob(
        blob => resolve(new File([blob], 'image.jpg', { type: 'image/jpeg' })),
        'image/jpeg', quality
      );
    };
    img.src = url;
  });
}

async function uploadImg(input, hiddenId, previewId, labelId) {
  const file = input.files[0];
  if (!file) return;

  const allowed = ['image/jpeg', 'image/png', 'image/gif', 'image/webp'];
  if (!allowed.includes(file.type)) {
    alert('Tuetut kuvamuodot: JPG, PNG, GIF, WebP');
    input.value = '';
    return;
  }

  const lbl = document.getElementById(labelId);
  lbl.style.opacity = '0.5';

  let resized;
  try { resized = await resizeImage(file); } catch (e) { lbl.style.opacity = ''; alert('Kuvan käsittely epäonnistui: ' + e.message); return; }

  const formData = new FormData();
  formData.append('file', resized, resized.name || 'image.jpg');
  try {
    const res = await fetch('upload.php', { method: 'POST', body: formData });
    const text = await res.text();
    let data;
    try { data = JSON.parse(text); } catch(e) { throw new Error('Palvelin vastasi (HTTP ' + res.status + '): ' + (text.slice(0, 200) || '(tyhjä)')); }
    if (data.error) throw new Error(data.error);
    document.getElementById(hiddenId).value = data.url;
    const prev = document.getElementById(previewId);
    prev.src = data.url;
    prev.style.display = 'block';
    lbl.classList.add('has-image');
  } catch (e) {
    alert('Kuvan lataus epäonnistui: ' + e.message);
  } finally {
    lbl.style.opacity = '';
  }
}

function showSubError(msg) {
  const el = document.getElementById('sub-error');
  el.textContent = msg;
  el.style.display = 'block';
}

async function submitPublicPost() {
  document.getElementById('sub-error').style.display = 'none';

  // Honeypot
  if (document.getElementById('sub-honeypot').value) return;

  const title = document.getElementById('sub-title').value.trim();
  if (!title) { showSubError('Anna julkaisulle otsikko.'); return; }

  if (!document.getElementById('sub-img1').value) {
    showSubError('Lisää vähintään 1 kuva julkaisuun.');
    return;
  }

  // CAPTCHA
  const captchaVal = parseInt(document.getElementById('sub-captcha-input').value, 10);
  if (captchaVal !== submitCaptchaAnswer) {
    showSubError('Väärä vastaus captchaan!');
    document.getElementById('sub-captcha-input').value = '';
    generateSubmitCaptcha();
    return;
  }

  const category    = document.getElementById('sub-category').value;
  const subVal      = document.getElementById('sub-subcategory')?.value || '';
  const subcategory = subVal ? [subVal] : [];
  const cat         = APP.categories.find(c => c.id === category);
  const emoji       = cat?.emoji || '📝';
  const author      = document.getElementById('sub-author').value.trim() || 'Vieras';
  const desc        = document.getElementById('sub-desc').value.trim();
  const images      = [
    document.getElementById('sub-img1').value.trim(),
    document.getElementById('sub-img2').value.trim(),
    document.getElementById('sub-img3').value.trim(),
  ].filter(Boolean);

  const submittedBy = APP.user
    ? { userId: APP.user.id, nickname: APP.user.nickname, validated: true }
    : { guestCode: Math.random().toString(36).slice(2, 8).toUpperCase(), validated: false };

  const post = {
    id: title.toLowerCase().normalize('NFD').replace(/[\u0300-\u036f]/g,'').replace(/\s+/g,'_').replace(/[^a-z0-9_]/g,'') + '_' + Date.now(),
    title, emoji, category, subcategory, author, desc, images,
    type: submitType,
    submittedBy,
  };

  if (submitType === 'recipe') {
    post.time        = document.getElementById('sub-time').value.trim();
    post.servings    = document.getElementById('sub-servings').value.trim();
    post.ingredients = document.getElementById('sub-ingredients').value.split('\n').map(s => s.trim()).filter(Boolean);
    post.steps       = document.getElementById('sub-steps').value.split('\n').map(s => s.trim()).filter(Boolean);
  } else {
    post.body = document.getElementById('sub-body').value.trim();
  }

  const btn = document.querySelector('.submit-btn');
  btn.disabled = true;
  btn.textContent = 'Lähetetään...';

  const data = await apiPost('add_post', { post });

  btn.disabled = false;
  btn.textContent = '📨 Lähetä julkaisu';

  if (data.error) { showSubError(data.error); return; }

  // Update local state
  APP.posts.push(post);

  closeSubmitModal();
  renderCards();
  renderCategoryFilters();

  // Reset form fields
  ['sub-title','sub-author','sub-desc','sub-img1','sub-img2','sub-img3',
   'sub-time','sub-servings','sub-ingredients','sub-steps','sub-body'].forEach(id => {
    const el = document.getElementById(id);
    if (el) el.value = '';
  });
  [1,2,3].forEach(i => {
    const prev = document.getElementById(`sub-prev${i}`);
    const lbl  = document.getElementById(`sub-lbl${i}`);
    if (prev) { prev.src = ''; prev.style.display = 'none'; }
    if (lbl) lbl.classList.remove('has-image');
  });

  document.getElementById('posts')?.scrollIntoView({ behavior: 'smooth' });
}

// ===========================
// CONTACT FORM
// ===========================
// ===========================
// CONTACT FORM
// ===========================
async function handleSubmit(e) {
  e.preventDefault();
  const btn = e.target.querySelector('button[type="submit"]');
  const name = document.getElementById('contact-name').value.trim();
  const email = document.getElementById('contact-email').value.trim();
  const message = document.getElementById('contact-msg').value.trim();
  btn.disabled = true;
  try {
    await apiPost('contact', { name, email, message });
    btn.textContent = t('msg_sent');
    btn.style.background = '#5c8a4a';
    e.target.reset();
    setTimeout(() => { btn.textContent = t('send_btn'); btn.style.background = ''; btn.disabled = false; }, 4000);
  } catch {
    btn.textContent = t('msg_error');
    btn.style.background = '#c04040';
    setTimeout(() => { btn.textContent = t('send_btn'); btn.style.background = ''; btn.disabled = false; }, 4000);
  }
}

// ===========================
// INIT
// ===========================
// COPY INGREDIENTS
// ===========================
function copyIngredients(postId) {
  const p = APP.posts.find(x => x.id === postId);
  if (!p?.ingredients?.length) return;
  const text = p.title + '\n\nOstoslista:\n' + p.ingredients.map(i => '• ' + i).join('\n');
  navigator.clipboard.writeText(text).then(() => {
    const btn = document.querySelector('.copy-list-btn');
    if (btn) { btn.textContent = '✅ Kopioitu!'; setTimeout(() => { btn.textContent = '📋 Kopioi ostoslista'; }, 2000); }
  }).catch(() => {});
}

// ===========================
// LOCAL LIKES PERSISTENCE
// ===========================
function getLocalLikes() {
  try {
    const v = JSON.parse(localStorage.getItem('tykkaafi_likes') || '[]');
    return Array.isArray(v) ? v : [];
  } catch { return []; }
}
function saveLocalLikes(arr) {
  try { localStorage.setItem('tykkaafi_likes', JSON.stringify(arr)); } catch {}
}

// ===========================
// AUTH
// ===========================
let authMode = 'login';
let authCaptchaAnswer = 0;

function generateAuthCaptcha() {
  const a = Math.floor(Math.random() * 9) + 1;
  const b = Math.floor(Math.random() * 9) + 1;
  authCaptchaAnswer = a + b;
  const qEl = document.getElementById('auth-captcha-question');
  if (qEl) qEl.textContent = `Laske: ${a} + ${b} = ?`;
}

function openAuthModal(mode = 'login') {
  authMode = mode;
  renderAuthForm();
  document.getElementById('authOverlay').classList.add('open');
  document.body.style.overflow = 'hidden';
  if (mode === 'register') generateAuthCaptcha();
}

function closeAuthModal() {
  document.getElementById('authOverlay').classList.remove('open');
  document.body.style.overflow = '';
}

function renderAuthForm() {
  const isLogin = authMode === 'login';
  document.getElementById('authContent').innerHTML = `
    <h2>${isLogin ? t('login_title') : t('register_title')}</h2>
    <div class="form-group">
      <label>${t('nickname_ph')}</label>
      <input type="text" id="auth-nickname" placeholder="${t('nickname_ph')}" maxlength="30" />
    </div>
    ${!isLogin ? `<div class="form-group">
      <label>${t('email_ph_reg')}</label>
      <input type="email" id="auth-email" placeholder="${t('email_ph_reg')}" maxlength="100" />
    </div>` : ''}
    <div class="form-group">
      <label>${t('password_ph')}</label>
      <input type="password" id="auth-password" placeholder="${t('password_ph')}" maxlength="100" />
    </div>
    ${!isLogin ? `
      <input type="text" name="website" id="auth-honeypot" tabindex="-1" autocomplete="off" style="display:none" />
      <div class="captcha-row">
        <label class="captcha-label" id="auth-captcha-question"></label>
        <input type="number" id="auth-captcha-input" placeholder="Vastaus" required min="0" max="99" style="width:100px" />
      </div>
    ` : ''}
    <p class="auth-error" id="auth-error"></p>
    <button class="submit-btn" onclick="submitAuth()">${isLogin ? t('login_submit') : t('register_submit')}</button>
    <p class="auth-switch" onclick="openAuthModal('${isLogin ? 'register' : 'login'}')">
      ${isLogin ? t('switch_to_register') : t('switch_to_login')}
    </p>
  `;
}

async function submitAuth() {
  const errEl = document.getElementById('auth-error');
  errEl.textContent = '';
  errEl.style.display = 'none';

  const nickname = document.getElementById('auth-nickname').value.trim();
  const password = document.getElementById('auth-password').value;
  const emailEl  = document.getElementById('auth-email');
  const email    = emailEl ? emailEl.value.trim() : '';

  if (!nickname || !password) {
    errEl.textContent = t('auth_fields_required');
    errEl.style.display = 'block';
    return;
  }

  if (authMode === 'register') {
    // Honeypot
    const hp = document.getElementById('auth-honeypot');
    if (hp && hp.value) return;

    // CAPTCHA
    const captchaVal = parseInt(document.getElementById('auth-captcha-input').value, 10);
    if (captchaVal !== authCaptchaAnswer) {
      errEl.textContent = 'Väärä vastaus captchaan!';
      errEl.style.display = 'block';
      document.getElementById('auth-captcha-input').value = '';
      generateAuthCaptcha();
      return;
    }
  }

  const action = authMode === 'login' ? 'user_login' : 'user_register';
  const body = { nickname, password };
  if (authMode === 'register') body.email = email;

  const data = await apiPost(action, body);
  if (data.error) {
    errEl.textContent = data.error;
    errEl.style.display = 'block';
    return;
  }

  APP.user = data.user;
  if (data.user.likes?.length) {
    APP.userLikes = [...new Set([...APP.userLikes, ...data.user.likes])];
    saveLocalLikes(APP.userLikes);
  }

  closeAuthModal();
  updateUserUI();
  renderCards();
}

async function logoutUser() {
  await apiPost('user_logout');
  APP.user = null;
  APP.showOnlyLiked = false;
  updateUserUI();
  renderCards();
  filterPosts();
}

function updateUserUI() {
  const container = document.getElementById('userArea');
  if (!container) return;

  if (APP.user) {
    container.innerHTML = `
      <span class="user-greeting">${t('logged_in_as')} <strong>${APP.user.nickname}</strong></span>
      <button class="user-btn logout-btn" onclick="logoutUser()">${t('logout_btn')}</button>
    `;
  } else {
    container.innerHTML = `
      <button class="user-btn login-btn" onclick="openAuthModal('login')">${t('login_btn')}</button>
      <button class="user-btn register-btn" onclick="openAuthModal('register')">${t('register_btn')}</button>
    `;
  }
  updateLikesFilterBtn();
}

// ===========================
// LIKES FILTER
// ===========================
function updateLikesFilterBtn() {
  const btn = document.getElementById('likesFilterBtn');
  if (!btn) return;
  btn.textContent = APP.showOnlyLiked ? ('❤️ ' + t('my_likes_btn').replace('❤️ ', '') + ' ✓') : t('my_likes_btn');
  btn.classList.toggle('active', APP.showOnlyLiked);
}

function toggleLikesFilter() {
  APP.showOnlyLiked = !APP.showOnlyLiked;
  updateLikesFilterBtn();
  filterPosts();
}

// ===========================
async function init() {
  try {
    const [postsData, catsData, likesData, userData] = await Promise.all([
      apiGet('posts'),
      apiGet('categories'),
      apiGet('likes'),
      apiGet('user_check'),
    ]);
    APP.posts      = postsData.posts      || [];
    APP.categories = catsData.categories  || [];
    APP.likes      = likesData.likes      || {};

    if (userData.loggedIn && userData.user) {
      APP.user = userData.user;
      const serverLikes = Array.isArray(userData.user.likes) ? userData.user.likes : [];
      const localLikes  = getLocalLikes();
      APP.userLikes = [...new Set([...serverLikes, ...localLikes])];
    } else {
      const serverLikes = Array.isArray(likesData.userLikes) ? likesData.userLikes : [];
      const localLikes  = getLocalLikes();
      APP.userLikes = [...new Set([...serverLikes, ...localLikes])];
    }
  } catch (e) {
    console.error('API virhe:', e);
  }
  applyTranslations();
  updateUserUI();
  renderCategoryFilters();
  renderSubFilters();
  renderCards();
}

init();
