import { showNotification } from "../notification.js";
import { refreshHud } from "../hud.js";
/* ── Einstiegspunkt ─────────────────────────────── */
export async function loadMine(buildingId) {
const actionsTab = document.getElementById("tab-actions");
if (!actionsTab) return;
actionsTab.innerHTML = `
Lade Mineninfo...
`;
await renderMineStatus(buildingId);
}
/* ─────────────────────────────────────────────────
Haupt-Render-Funktion
───────────────────────────────────────────────── */
async function renderMineStatus(buildingId) {
const actionsTab = document.getElementById("tab-actions");
try {
const res = await fetch("/api/mine/" + buildingId + "/status");
if (!res.ok) throw new Error("API Fehler");
const data = await res.json();
if (data.error) {
actionsTab.innerHTML = "" + data.error + "
";
return;
}
actionsTab.innerHTML =
"" +
renderHeader(data) +
renderDivider() +
(!data.selected_resource
? renderResourceSelector(data, buildingId)
: renderActiveSession(data, buildingId)
) +
"
";
if (data.selected_resource) {
startSessionCountdown(buildingId, data);
}
} catch (err) {
console.error("Mine Fehler:", err);
actionsTab.innerHTML =
"Fehler beim Laden der Mineninfo.
";
}
}
/* ─────────────────────────────────────────────────
Header
───────────────────────────────────────────────── */
function renderHeader(data) {
let cycleText = "Keine Ressource gewählt";
if (data.selected_resource) {
if (data.is_full) cycleText = "Session beendet – bitte abholen!";
else if (data.cycles > 0) cycleText = data.cycles + "x Zyklus bereit";
else cycleText = "Läuft...";
}
return (
""
);
}
/* ─────────────────────────────────────────────────
Startscreen (keine aktive Session)
───────────────────────────────────────────────── */
function renderResourceSelector(data, buildingId) {
return (
"Ressource wählen
" +
"Wähle eine Ressource für die nächsten " + data.session_hours + "h.
" +
renderResourceGrid(data.production, null, buildingId, "select")
);
}
/* ─────────────────────────────────────────────────
Aktive Session
───────────────────────────────────────────────── */
function renderActiveSession(data, buildingId) {
return (
renderCurrentProduction(data) +
renderDivider() +
renderQueueSection(data, buildingId) +
renderDivider() +
renderCollectSection(data, buildingId)
);
}
/* ─────────────────────────────────────────────────
Aktuelle Produktion
Zwei Timer:
1. Session-Countdown → wie lange läuft die 5h noch?
2. Zyklus-Countdown → wann ist der nächste Zyklus fertig?
───────────────────────────────────────────────── */
function renderCurrentProduction(data) {
const sessionMin = Math.floor(data.session_seconds_left / 60);
const sessionSec = data.session_seconds_left % 60;
const cycleMin = Math.floor(data.next_cycle_in_seconds / 60);
const cycleSec = data.next_cycle_in_seconds % 60;
/* Fortschritt: wieviele Zyklen von max wurden in der Session erreicht */
const progressPct = Math.min(100, Math.round((data.cycles / data.max_cycles) * 100));
return (
"Aktuelle Session – " + data.session_hours + "h
" +
"" +
"" + resourceIcon(data.selected_resource) + "" +
"" + resourceLabel(data.selected_resource) + "" +
"" + data.available_amount + "" +
"
" +
/* Fortschrittsbalken */
"" +
/* Session-Timer (läuft immer durch) */
"" +
"Session endet in" +
(data.is_full
? "FERTIG"
: "" +
sessionMin + "m " + sessionSec + "s"
) +
"
" +
/* Zyklus-Timer (nur wenn Session noch läuft und noch Zyklen kommen) */
(!data.is_full
? "" +
"Nächster Zyklus in" +
"" +
cycleMin + "m " + cycleSec + "s" +
"
"
: ""
)
);
}
/* ─────────────────────────────────────────────────
Warteschlange
───────────────────────────────────────────────── */
function renderQueueSection(data, buildingId) {
const { loop_queue, loop_slots_free, loop_slots_used,
loop_cost_gems, can_afford_loop, player_gems } = data;
let html =
"Warteschlange" +
" (" + loop_slots_used + "/4)
";
loop_queue.forEach((res, i) => {
html +=
"" +
"" + (i + 1) + "." +
"" + resourceIcon(res) + "" +
"" + resourceLabel(res) + "" +
"" + data.session_hours + "h" +
"
";
});
if (loop_slots_free > 0) {
const nextPos = loop_slots_used + 1;
html +=
"" +
"
" +
"
" +
"
Welche Ressource soll in Slot " + nextPos + " abgebaut werden?
" +
renderResourceGrid(data.production, null, buildingId, "loop") +
"
" +
"
";
}
if (loop_slots_free === 0) {
html += "Warteschlange voll – 4 Schleifen aktiv.
";
}
return html;
}
/* ─────────────────────────────────────────────────
Ressourcen-Raster
───────────────────────────────────────────────── */
function renderResourceGrid(production, activeResource, buildingId, mode) {
const buttons = production.map(r => {
const isActive = r.resource === activeResource;
return (
""
);
}).join("");
return "" + buttons + "
";
}
/* ─────────────────────────────────────────────────
Collect-Button
───────────────────────────────────────────────── */
function renderCollectSection(data, buildingId) {
return (
"" +
"" +
"
"
);
}
function renderDivider() {
return "";
}
/* ─────────────────────────────────────────────────
Event: Loop-Picker togglen
───────────────────────────────────────────────── */
document.addEventListener("click", (e) => {
const btn = e.target.closest("#mine-queue-toggle");
if (!btn || btn.disabled) return;
const picker = document.getElementById("mine-loop-picker");
if (!picker) return;
const isOpen = picker.style.display !== "none";
picker.style.display = isOpen ? "none" : "block";
btn.classList.toggle("mine-btn-add-loop-open", !isOpen);
});
/* ─────────────────────────────────────────────────
Event: Ressource wählen / Schleife buchen
───────────────────────────────────────────────── */
document.addEventListener("click", async (e) => {
const btn = e.target.closest(".mine-res-btn");
if (!btn || btn.disabled || btn.classList.contains("mine-res-btn-active")) return;
const resource = btn.dataset.resource;
const buildingId = btn.dataset.building;
const mode = btn.dataset.mode;
document.querySelectorAll(".mine-res-btn").forEach(b => (b.disabled = true));
const endpoint = mode === "loop"
? "/api/mine/" + buildingId + "/loop"
: "/api/mine/" + buildingId + "/select";
try {
const res = await fetch(endpoint, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ resource }),
});
if (!res.ok) throw new Error("API Fehler");
const data = await res.json();
if (data.error) {
showNotification(data.error, "Mine", "⛏️");
await renderMineStatus(buildingId);
return;
}
if (mode === "loop") {
showNotification(
"Schleife hinzugefügt!\n" + resourceLabel(resource) + " – 5h\n" +
"Noch " + data.loop_slots_free + " Slot(s) frei.",
"Mine", "💎"
);
} else {
showNotification(
resourceLabel(resource) + " ausgewählt.\n5h Session startet jetzt.",
"Mine", "⛏️"
);
}
await renderMineStatus(buildingId);
if (mode === "loop") await refreshHud();
} catch (err) {
console.error("Mine Fehler:", err);
await renderMineStatus(buildingId);
}
});
/* ─────────────────────────────────────────────────
Event: Abholen
───────────────────────────────────────────────── */
document.addEventListener("click", async (e) => {
const btn = e.target.closest("#mine-collect-btn");
if (!btn || btn.disabled) return;
const buildingId = btn.dataset.building;
btn.disabled = true;
btn.textContent = "Wird abgeholt...";
try {
const res = await fetch("/api/mine/" + buildingId + "/collect", {
method: "POST",
});
if (!res.ok) throw new Error("API Fehler");
const data = await res.json();
if (data.error) {
showNotification(
data.ready_in_display
? "Noch nicht bereit.\nBereit in: " + data.ready_in_display
: data.error,
"Mine", "⛏️"
);
await renderMineStatus(buildingId);
return;
}
const c = data.collected;
let msg = "Abgeholt!\n" + resourceLabel(c.resource) + ": +" + c.amount;
if (data.session_ended) {
msg += data.next_resource
? "\n\nNächste Session: " + resourceLabel(data.next_resource) + " (5h)"
: "\n\nKeine weiteren Schleifen – neue Ressource wählen.";
}
/* Session läuft noch → kein Hinweis nötig */
showNotification(msg, "Mine", "⛏️");
await renderMineStatus(buildingId);
await refreshHud();
} catch (err) {
console.error("Abholen Fehler:", err);
showNotification("Fehler beim Abholen. Bitte erneut versuchen.", "Fehler", "⚠️");
await renderMineStatus(buildingId);
}
});
/* ─────────────────────────────────────────────────
Zwei parallele Countdowns:
1. Session-Countdown (mine-session-countdown)
2. Zyklus-Countdown (mine-cycle-countdown)
───────────────────────────────────────────────── */
let sessionInterval = null;
let cycleInterval = null;
function startSessionCountdown(buildingId, data) {
if (sessionInterval) clearInterval(sessionInterval);
if (cycleInterval) clearInterval(cycleInterval);
if (data.is_full) return;
/* Session-Timer */
sessionInterval = setInterval(() => {
const el = document.getElementById("mine-session-countdown");
if (!el) { clearInterval(sessionInterval); return; }
let secs = parseInt(el.dataset.seconds, 10) - 1;
if (secs < 0) secs = 0;
el.dataset.seconds = secs;
el.textContent = Math.floor(secs / 60) + "m " + (secs % 60) + "s";
if (secs === 0) {
clearInterval(sessionInterval);
clearInterval(cycleInterval);
renderMineStatus(buildingId); // Session abgelaufen → neu rendern
}
}, 1000);
/* Zyklus-Timer */
cycleInterval = setInterval(() => {
const el = document.getElementById("mine-cycle-countdown");
if (!el) { clearInterval(cycleInterval); return; }
let secs = parseInt(el.dataset.seconds, 10) - 1;
if (secs < 0) secs = 0;
el.dataset.seconds = secs;
el.textContent = Math.floor(secs / 60) + "m " + (secs % 60) + "s";
if (secs === 0) {
clearInterval(cycleInterval);
renderMineStatus(buildingId); // Neuer Zyklus → Menge aktualisieren
}
}, 1000);
}
/* ─────────────────────────────────────────────────
Icons & Labels
───────────────────────────────────────────────── */
function resourceIcon(resource) {
const imgMap = {
iron: "/images/items/eisen.png",
gold: "/images/items/goldmuenze.png",
wood: "/images/items/holz.png",
stone: "/images/items/stein.png",
};
if (imgMap[resource]) {
return (
"" +
"
" +
""
);
}
return "📦";
}
function resourceLabel(resource) {
const map = { gold: "Gold", iron: "Eisen", stone: "Stein", wood: "Holz" };
return map[resource] || resource;
}