require('dotenv').config();
const express = require('express');
const cors = require('cors');
const fs = require('fs');
const path = require('path');
// MariaDB routes
const playerRoutes = require('./routes/playerRoutes');
const sessionRoutes = require('./routes/sessionRoutes');
const shopRoutes = require('./routes/shopRoutes');
const rulesRoutes = require('./routes/rulesRoutes');
const bestiaryRoutes = require('./routes/bestiaryRoutes');
const weaponsRoutes = require('./routes/weaponsRoutes');
const rulesStagingRoutes = require('./routes/rulesStagingRoutes');
const missionRoutes = require('./routes/missionRoutes');
const simulationRoutes = require('./routes/simulationRoutes');
const errorRoutes = require('./routes/errorRoutes');
const musicRoutes = require('./routes/musicRoutes');
// const rulesRoutes = require('./routes/rulesRoutes-simple');

const gmkitDir = path.join(__dirname, '..', 'data', 'gamemasters_kit');

// Initialize MariaDB
require('./mariadb');

console.log('Routes loaded:', {
  shopRoutes: typeof shopRoutes,
  rulesRoutes: typeof rulesRoutes,
  bestiaryRoutes: typeof bestiaryRoutes,
  weaponsRoutes: typeof weaponsRoutes
});

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

// Middleware
app.use(express.json());
app.use(cors());

// API Routes (before static files)
console.log('Registering API routes...');
// Player routes now working with MariaDB
try {
  console.log('Registering /api/players');
  app.use('/api/players', playerRoutes);
  console.log('Players routes registered');
} catch (e) {
  console.error('Error mounting /api/players:', e && e.stack ? e.stack : e);
  throw e;
}
try {
  console.log('Registering /api/sessions');
  app.use('/api/sessions', sessionRoutes);
  console.log('Sessions routes registered');
} catch (e) {
  console.error('Error mounting /api/sessions:', e && e.stack ? e.stack : e);
  throw e;
}
try {
  console.log('Registering /api/shop');
  app.use('/api/shop', shopRoutes);
  console.log('Shop routes registered');
} catch (e) {
  console.error('Error mounting /api/shop:', e && e.stack ? e.stack : e);
  throw e;
}
try {
  console.log('Registering /api/rules');
  app.use('/api/rules', rulesRoutes);
  console.log('Rules routes registered');
} catch (e) {
  console.error('Error mounting /api/rules:', e && e.stack ? e.stack : e);
  throw e;
  }

  try {
    console.log('Registering /api/weapons');
    app.use('/api/weapons', weaponsRoutes);
    console.log('Weapons routes registered');
  } catch (e) {
    console.error('Error mounting /api/weapons:', e && e.stack ? e.stack : e);
    throw e;
  }

  try {
    console.log('Registering /api/bestiary');
    app.use('/api/bestiary', bestiaryRoutes);
    console.log('Bestiary routes registered');
  } catch (e) {
    console.error('Error mounting /api/bestiary:', e && e.stack ? e.stack : e);
    throw e;
  }

  try {
    console.log('Registering /api/rules/staging');
    app.use('/api/rules/staging', rulesStagingRoutes);
    console.log('Rules staging routes registered');
  } catch (e) {
    console.error('Error mounting /api/rules/staging:', e && e.stack ? e.stack : e);
  }

  try {
    console.log('Registering /api/missions');
    app.use('/api/missions', missionRoutes);
    console.log('Mission routes registered');
  } catch (e) {
    console.error('Error mounting /api/missions:', e && e.stack ? e.stack : e);
  }

  try {
    console.log('Registering /api/simulations');
    app.use('/api/simulations', simulationRoutes);
    console.log('Simulation routes registered');
  } catch (e) {
    console.error('Error mounting /api/simulations:', e && e.stack ? e.stack : e);
  }

  try {
    console.log('Registering /api/errors');
    app.use('/api/errors', errorRoutes);
    console.log('Error report routes registered');
  } catch (e) {
    console.error('Error mounting /api/errors:', e && e.stack ? e.stack : e);
  }

  try {
    console.log('Registering /api/music');
    app.use('/api/music', musicRoutes);
    console.log('Music routes registered');
  } catch (e) {
    console.error('Error mounting /api/music:', e && e.stack ? e.stack : e);
  }

  // Expose gamemaster kit files and a simple listing API for GM-only resources
  try {
    console.log('Registering /api/gmkit and /gmkit static');
    app.get('/api/gmkit/list', (req, res) => {
      try {
        if (!fs.existsSync(gmkitDir)) return res.json([]);
        const files = fs.readdirSync(gmkitDir).filter(f => !f.startsWith('.'));
        const list = files.map(f => {
          const filePath = path.join(gmkitDir, f);
          let stat = null;
          try { stat = fs.statSync(filePath); } catch (e) { stat = null; }
          const ext = path.extname(f).toLowerCase().replace('.', '');
          // minimal mime mapping
          const mimeMap = { png: 'image/png', jpg: 'image/jpeg', jpeg: 'image/jpeg', gif: 'image/gif', svg: 'image/svg+xml', pdf: 'application/pdf' };
          const mime = mimeMap[ext] || 'application/octet-stream';
          return { name: f, url: `/gmkit/${encodeURIComponent(f)}`, size: stat ? stat.size : null, mime, ext };
        });
        res.json(list);
      } catch (err) {
        console.error('Failed to list gmkit files', err);
        res.status(500).json({ error: 'Failed to list gmkit files' });
      }
    });

    app.use('/gmkit', express.static(gmkitDir));
    console.log('GMKit routes registered');
  } catch (e) {
    console.error('Error mounting /api/gmkit or /gmkit:', e && e.stack ? e.stack : e);
  }

  // Simple JSON base64 upload endpoint for GM Kit files (GM-only via session)
  const { requireGM } = require('./auth');
  app.post('/api/gmkit/upload', express.json({ limit: '20mb' }), async (req, res) => {
    try {
      if (!(await requireGM(req, res))) return;
      const { name, b64 } = req.body || {};
      if (!name || !b64) return res.status(400).json({ error: 'Missing name or b64 body' });
      if (!fs.existsSync(gmkitDir)) fs.mkdirSync(gmkitDir, { recursive: true });
      // Basic sanitize name
      const safeName = name.replace(/[^a-zA-Z0-9_.-]/g, '_');
      const filePath = path.join(gmkitDir, safeName);
      // Decode base64 (allow data: prefix)
      const m = b64.match(/^data:([\w/+-\.]+);base64,(.*)$/);
      const data = m ? m[2] : b64;
      const buf = Buffer.from(data, 'base64');
      fs.writeFileSync(filePath, buf);
      return res.json({ success: true, name: safeName, url: `/gmkit/${encodeURIComponent(safeName)}` });
    } catch (err) {
      console.error('GMKit upload failed', err);
      return res.status(500).json({ error: 'Upload failed' });
    }
  });

// Add bestiary copy endpoint
app.post('/api/copy-bestiary', (req, res) => {
  try {
    const { copyBestiaryToPublic } = require('../scripts/copy-bestiary-live');
    const success = copyBestiaryToPublic();
    if (success) {
      res.json({ success: true, message: 'Bestiary files updated successfully' });
    } else {
      res.status(500).json({ success: false, message: 'Failed to update bestiary files' });
    }
  } catch (error) {
    console.error('Error in copy-bestiary endpoint:', error);
    res.status(500).json({ success: false, message: 'Internal server error', error: error.message });
  }
});

// Local Ollama narrator — used by MissionSimTab callCopilot()
app.post('/api/narrate', express.json({ limit: '4mb' }), async (req, res) => {
  try {
    const { prompt, systemPrompt } = req.body || {};
    if (!prompt) return res.status(400).json({ error: 'Missing prompt' });
    const ollamaBase = process.env.OLLAMA_BASE || 'http://localhost:11434';
    const model = process.env.NARRATOR_MODEL || 'qwen3.5:latest';
    const messages = [];
    if (systemPrompt) messages.push({ role: 'system', content: systemPrompt });
    messages.push({ role: 'user', content: `/no_think ${prompt}` });
    const response = await fetch(`${ollamaBase}/api/chat`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ model, messages, stream: false, think: false }),
    });
    if (!response.ok) {
      const errText = await response.text();
      return res.status(502).json({ error: 'Ollama error', detail: errText });
    }
    const data = await response.json();
    const text = data.message?.content || data.response || '';
    return res.json({ text });
  } catch (err) {
    console.error('Narrator error:', err);
    return res.status(500).json({ error: 'Narrator failed', detail: err.message });
  }
});

// Serve static files from build directory (React app)
const buildDir = path.join(__dirname, '..', 'build');
app.use(express.static(buildDir));

// Serve weapon images directly from public/ so new images appear without rebuild
const weaponImagesDir = path.join(__dirname, '..', 'public', 'weapon-images');
fs.mkdirSync(weaponImagesDir, { recursive: true });
app.use('/weapon-images', express.static(weaponImagesDir));

// Serve uploaded avatars from public/avatars
const avatarsDir = path.join(__dirname, '..', 'public', 'avatars');
if (!fs.existsSync(avatarsDir)) {
  fs.mkdirSync(avatarsDir, { recursive: true });
}
app.use('/avatars', express.static(avatarsDir));

// Serve mood music files from media/music
const musicDir = path.join(__dirname, '..', 'media', 'music');
if (!fs.existsSync(musicDir)) {
  fs.mkdirSync(musicDir, { recursive: true });
}
app.use('/music', express.static(musicDir));

// Catch-all handler for React Router (must be after API routes)
// app.get('*', (req, res) => {
//   res.sendFile(path.join(buildDir, 'index.html'));
// });

// Graceful shutdown - MariaDB connections are handled by the pool
process.on('SIGINT', () => {
  console.log('Shutting down server...');
  process.exit(0);
});

process.on('SIGTERM', () => {
  console.log('Shutting down server...');
  process.exit(0);
});

// If a React build exists, serve it at root and fallback to index.html for client-side routing
const indexHtml = path.join(buildDir, 'index.html');
if (fs.existsSync(indexHtml)) {
  app.get('/', (req, res) => res.sendFile(indexHtml));

  // Catch-all for client-side routes (must be after API routes)
  // Middleware fallback for client-side routing: serve index.html for non-API and non-avatar paths.
  // Use a plain middleware (no path) to avoid route string parsing by path-to-regexp.
  app.use((req, res, next) => {
    if (req.path.startsWith('/api/') || req.path.startsWith('/avatars/') || req.path.startsWith('/music/') || req.path.startsWith('/gmkit/')) return next();
    return res.sendFile(indexHtml);
  });
} else {
  // Root route for friendly message when no build is present
  app.get('/', (req, res) => {
    res.send('Deathwatch Roller API is running with MariaDB. Use /api/shop for shop data.');
  });
}

// Routes have already been registered above - no need to duplicate

// Start Server
app.listen(PORT, '0.0.0.0', () => {
  console.log(`Server running on http://0.0.0.0:${PORT}`);
  console.log('Using MariaDB database');
});

module.exports = app;
