/*
  server.js — Richland Class of 1976 Reunion
  ============================================
  Serves the static HTML/CSS/image files and exposes a small
  REST API backed by MongoDB (via Mongoose).

  Start:  node server.js
  Dev:    npx nodemon server.js   (auto-restarts on file changes)

  API endpoints
  ─────────────
  GET  /api/sponsors          → all 2026 sponsor slots
  PUT  /api/sponsors/:id      → upsert one slot  { name, img }
  DEL  /api/sponsors/:id      → clear one slot

  GET  /api/memory            → all 1976 memory-wall tiles
  PUT  /api/memory/:idx       → upsert one tile  { img }
  DEL  /api/memory/:idx       → clear one tile

  Static files are served from the same directory as this file,
  so index.html, alumni_info.html, sponsor_page.html, styles.css
  and meijer_logo_1976.png are all served automatically.
*/

'use strict';

require('dotenv').config();

const express  = require('express');
const mongoose = require('mongoose');
const path     = require('path');

const app  = express();
const PORT = process.env.PORT || 3000;

/* ── Middleware ─────────────────────────────────────────────── */

app.use(express.json({ limit: '10mb' })); // base64 images can be large
app.use(express.urlencoded({ extended: true, limit: '10mb' }));

// Serve all static site files (HTML, CSS, images) from this folder
app.use(express.static(path.join(__dirname)));

/* ── MongoDB connection ─────────────────────────────────────── */

mongoose
  .connect(process.env.MONGO_URI || 'mongodb://127.0.0.1:27017/richland76')
  .then(() => console.log('MongoDB connected:', mongoose.connection.host))
  .catch(err => {
    console.error('MongoDB connection error:', err.message);
    process.exit(1);
  });

/* ── Mongoose schemas & models ──────────────────────────────── */

/*
  Sponsor slot — represents one 2026 sponsor card.
  slotId examples: "a0", "a1", "a2", "a3"  (anchor slots)
                   "b0" … "b9"              (small-business slots)
*/
const sponsorSchema = new mongoose.Schema({
  slotId: { type: String, required: true, unique: true }, // e.g. "a0", "b3"
  name:   { type: String, default: '' },
  img:    { type: String, default: '' }, // base64 data-URI  OR  a URL path
}, { timestamps: true });

const Sponsor = mongoose.model('Sponsor', sponsorSchema);

/*
  Memory wall tile — one of the 12 founding-sponsor image slots.
  idx is 0–11 matching the founding76 array order in the HTML.
*/
const memorySchema = new mongoose.Schema({
  idx: { type: Number, required: true, unique: true }, // 0–11
  img: { type: String, default: '' },                  // base64 data-URI
}, { timestamps: true });

const Memory = mongoose.model('Memory', memorySchema);

/* ── Helper ─────────────────────────────────────────────────── */

function handleError(res, err) {
  console.error(err);
  res.status(500).json({ error: err.message });
}

/* ── Sponsor routes ─────────────────────────────────────────── */

// GET /api/sponsors
// Returns an object keyed by slotId: { "a0": {name, img}, ... }
app.get('/api/sponsors', async (req, res) => {
  try {
    const docs   = await Sponsor.find({}).lean();
    const result = {};
    docs.forEach(d => {
      result[d.slotId] = { name: d.name, img: d.img };
    });
    res.json(result);
  } catch (err) { handleError(res, err); }
});

// PUT /api/sponsors/:id
// Body: { name: "Acme Corp", img: "data:image/png;base64,..." }
// Creates the slot if it doesn't exist, updates it if it does.
app.put('/api/sponsors/:id', async (req, res) => {
  try {
    const { name = '', img = '' } = req.body;
    const doc = await Sponsor.findOneAndUpdate(
      { slotId: req.params.id },
      { name, img },
      { upsert: true, new: true, runValidators: true }
    );
    res.json({ slotId: doc.slotId, name: doc.name, img: doc.img });
  } catch (err) { handleError(res, err); }
});

// DELETE /api/sponsors/:id
// Removes the slot document so the card goes back to "available".
app.delete('/api/sponsors/:id', async (req, res) => {
  try {
    await Sponsor.deleteOne({ slotId: req.params.id });
    res.json({ deleted: req.params.id });
  } catch (err) { handleError(res, err); }
});

/* ── Memory wall routes ─────────────────────────────────────── */

// GET /api/memory
// Returns an object keyed by idx: { "0": "data:image/...", "3": "..." }
app.get('/api/memory', async (req, res) => {
  try {
    const docs   = await Memory.find({}).lean();
    const result = {};
    docs.forEach(d => { result[d.idx] = d.img; });
    res.json(result);
  } catch (err) { handleError(res, err); }
});

// PUT /api/memory/:idx
// Body: { img: "data:image/png;base64,..." }
app.put('/api/memory/:idx', async (req, res) => {
  try {
    const idx = parseInt(req.params.idx, 10);
    if (isNaN(idx) || idx < 0 || idx > 11) {
      return res.status(400).json({ error: 'idx must be 0–11' });
    }
    const { img = '' } = req.body;
    const doc = await Memory.findOneAndUpdate(
      { idx },
      { img },
      { upsert: true, new: true, runValidators: true }
    );
    res.json({ idx: doc.idx, img: doc.img });
  } catch (err) { handleError(res, err); }
});

// DELETE /api/memory/:idx
app.delete('/api/memory/:idx', async (req, res) => {
  try {
    const idx = parseInt(req.params.idx, 10);
    await Memory.deleteOne({ idx });
    res.json({ deleted: idx });
  } catch (err) { handleError(res, err); }
});

/* ── Health check ───────────────────────────────────────────── */

app.get('/api/health', (req, res) => {
  res.json({
    status: 'ok',
    mongo: mongoose.connection.readyState === 1 ? 'connected' : 'disconnected',
    uptime: Math.round(process.uptime()) + 's',
  });
});

/* ── Catch-all: serve index.html for any unknown route ─────── */
// (Handles browser refreshes on sub-pages if you later add routing)
app.get('*', (req, res) => {
  res.sendFile(path.join(__dirname, 'index.html'));
});

/* ── Start server ───────────────────────────────────────────── */

app.listen(PORT, () => {
  console.log(`Server running at http://localhost:${PORT}`);
  console.log('Static files served from:', __dirname);
});
