const authView = document.querySelector("#authView");
const libraryView = document.querySelector("#libraryView");

const loginForm = document.querySelector("#loginForm");
const registerForm = document.querySelector("#registerForm");
const authMessage = document.querySelector("#authMessage");
const tabs = document.querySelectorAll("[data-auth-tab]");

const input = document.querySelector("#searchInput");
const searchButton = document.querySelector("#searchBtn");
const results = document.querySelector("#results");
const status = document.querySelector("#status");
const logoutButton = document.querySelector("#logoutBtn");
const userBadge = document.querySelector("#userBadge");

async function api(url, options = {}) {
  const response = await fetch(url, {
    credentials: "same-origin",
    headers: {
      "Content-Type": "application/json",
      ...(options.headers || {})
    },
    ...options
  });

  const data = await response.json().catch(() => ({
    ok: false,
    error: `HTTP ${response.status}`
  }));

  if (!response.ok || data.ok === false) {
    const error = new Error(
      data.error || `HTTP ${response.status}`
    );
    error.status = response.status;
    throw error;
  }

  return data;
}

function showAuth() {
  authView.classList.remove("hidden");
  libraryView.classList.add("hidden");
}

function showLibrary(user) {
  authView.classList.add("hidden");
  libraryView.classList.remove("hidden");

  userBadge.textContent =
    `@${user.username}`;
}

async function checkSession() {
  try {
    const data = await api("/api/auth/me");

    if (data.authenticated) {
      showLibrary(data.user);
      await search();
    } else {
      showAuth();
    }
  } catch {
    showAuth();
  }
}

function setAuthTab(tab) {
  tabs.forEach(button => {
    button.classList.toggle(
      "active",
      button.dataset.authTab === tab
    );
  });

  loginForm.classList.toggle(
    "hidden",
    tab !== "login"
  );

  registerForm.classList.toggle(
    "hidden",
    tab !== "register"
  );

  authMessage.textContent = "";
}

tabs.forEach(button => {
  button.addEventListener(
    "click",
    () => setAuthTab(
      button.dataset.authTab
    )
  );
});

loginForm.addEventListener(
  "submit",
  async event => {
    event.preventDefault();
    authMessage.textContent = "";

    try {
      const data = await api(
        "/api/auth/login",
        {
          method: "POST",
          body: JSON.stringify({
            username:
              document.querySelector(
                "#loginUsername"
              ).value,

            password:
              document.querySelector(
                "#loginPassword"
              ).value
          })
        }
      );

      showLibrary(data.user);
      await search();
    } catch (error) {
      authMessage.textContent =
        error.message;
    }
  }
);

registerForm.addEventListener(
  "submit",
  async event => {
    event.preventDefault();
    authMessage.textContent = "";

    try {
      const data = await api(
        "/api/auth/register",
        {
          method: "POST",
          body: JSON.stringify({
            username:
              document.querySelector(
                "#registerUsername"
              ).value,

            password:
              document.querySelector(
                "#registerPassword"
              ).value,

            registrationCode:
              document.querySelector(
                "#registrationCode"
              ).value
          })
        }
      );

      showLibrary(data.user);
      await search();
    } catch (error) {
      authMessage.textContent =
        error.message;
    }
  }
);

async function search() {
  const query =
    input.value.trim();

  status.textContent =
    query
      ? `Buscando "${query}"...`
      : "Últimos modelos";

  results.innerHTML =
    '<div class="empty">Buscando modelos...</div>';

  try {
    const data = await api(
      `/api/catalog/search?q=${encodeURIComponent(query)}`
    );

    render(data.results);

    status.textContent =
      data.count === 1
        ? "1 modelo encontrado"
        : `${data.count} modelos encontrados`;
  } catch (error) {
    if (error.status === 401) {
      showAuth();
      return;
    }

    status.textContent =
      "No se pudo consultar la biblioteca.";

    results.innerHTML =
      `<div class="empty">${escapeHtml(
        error.message
      )}</div>`;
  }
}

function render(items) {
  if (!items.length) {
    results.innerHTML =
      `
      <div class="empty">
        <div class="empty-icon">◌</div>
        <h3>No encontramos modelos</h3>
        <p>Prueba con otro nombre o término.</p>
      </div>
      `;
    return;
  }

  results.innerHTML =
    items.map(item => {

      const image =
        item.thumbnail_path
          ? `
            <img
              src="${item.thumbnail_path}"
              alt=""
              loading="lazy"
            >
            `
          : `
            <div class="noimage">
              <span>STL</span>
              <small>Sin vista previa</small>
            </div>
            `;

      const ext =
        (item.extension || "FILE")
          .replace(".", "")
          .toUpperCase();

      return `
        <article class="model-card">

          <div class="model-preview">
            ${image}

            <span class="format-badge">
              ${escapeHtml(ext)}
            </span>
          </div>

          <div class="model-body">
            <h3
              title="${escapeAttr(
                item.name || ""
              )}"
            >
              ${escapeHtml(
                item.name || "Modelo"
              )}
            </h3>

            <div class="model-meta">
              <span>
                ${item.size_bytes
                  ? formatBytes(
                      item.size_bytes
                    )
                  : ""}
              </span>

              <span>
                ${item.message_date
                  ? formatDate(
                      item.message_date
                    )
                  : ""}
              </span>
            </div>

            ${
              item.description
                ? `
                  <p class="model-desc">
                    ${escapeHtml(
                      item.description
                    )}
                  </p>
                  `
                : ""
            }

            <a
              class="download-button"
              href="/api/catalog/download/${encodeURIComponent(
                item.id
              )}"
            >
              <span>↓</span>
              Descargar
            </a>
          </div>
        </article>
      `;
    }).join("");
}

document.querySelectorAll(
  ".quick-searches button"
).forEach(button => {
  button.addEventListener(
    "click",
    () => {
      input.value =
        button.dataset.query;

      search();
    }
  );
});

searchButton.addEventListener(
  "click",
  search
);

input.addEventListener(
  "keydown",
  event => {
    if (
      event.key === "Enter"
    ) {
      search();
    }
  }
);

logoutButton.addEventListener(
  "click",
  async () => {
    try {
      await api(
        "/api/auth/logout",
        {
          method: "POST"
        }
      );
    } finally {
      showAuth();
    }
  }
);

function formatBytes(bytes) {
  if (!bytes) return "";

  const units =
    ["B", "KB", "MB", "GB"];

  let value =
    Number(bytes);

  let unit = 0;

  while (
    value >= 1024 &&
    unit < units.length - 1
  ) {
    value /= 1024;
    unit++;
  }

  return `${value.toFixed(
    unit ? 1 : 0
  )} ${units[unit]}`;
}

function formatDate(value) {
  const date =
    new Date(value);

  if (Number.isNaN(
    date.getTime()
  )) {
    return "";
  }

  return date.toLocaleDateString(
    "es",
    {
      day: "2-digit",
      month: "short"
    }
  );
}

function escapeHtml(value) {
  return String(value)
    .replace(
      /[&<>"']/g,
      char => ({
        "&": "&amp;",
        "<": "&lt;",
        ">": "&gt;",
        '"': "&quot;",
        "'": "&#039;"
      }[char])
    );
}

function escapeAttr(value) {
  return escapeHtml(value);
}

checkSession();
