'use strict';

const express = require('express');
const http = require('http');
const WebSocket = require('ws');
const path = require('path');
const fs = require('fs');
const morgan = require('morgan');
const cors = require('cors');

const { requireAuth } = require('./middleware/auth');
const { licenseMiddleware, checkLicense, getStatus } = require('./middleware/license');

const app = express();
const server = http.createServer(app);
const wss = new WebSocket.Server({ server, path: '/ws' });

// ─── Global WebSocket broadcast helpers ─────────────────────────────────────
global.wsClients = new Set();

global.broadcastLog = (message, level = 'info') => {
  const payload = JSON.stringify({
    type: 'log',
    level,
    message,
    timestamp: new Date().toISOString(),
  });
  global.wsClients.forEach(c => {
    if (c.readyState === WebSocket.OPEN) c.send(payload);
  });
};

global.broadcastEvent = (event, data = {}) => {
  const payload = JSON.stringify({
    type: 'event',
    event,
    data,
    timestamp: new Date().toISOString(),
  });
  global.wsClients.forEach(c => {
    if (c.readyState === WebSocket.OPEN) c.send(payload);
  });
};

wss.on('connection', ws => {
  global.wsClients.add(ws);
  ws.send(JSON.stringify({ type: 'connected', message: 'DeployPro connected' }));
  ws.on('close', () => global.wsClients.delete(ws));
  ws.on('error', () => global.wsClients.delete(ws));
});

// ─── Middleware ───────────────────────────────────────────────────────────────
app.use(cors());
app.use(morgan('dev'));
app.use(express.json({ limit: '10mb' }));
app.use(express.urlencoded({ extended: true }));
app.use(express.static(path.join(__dirname, 'public'), { index: false }));

// ─── License status / activation (public) ────────────────────────────────────
app.get('/api/license/status', (_req, res) => {
  const s = getStatus();
  res.json(s || { valid: false, mode: 'unknown' });
});

app.post('/api/license/save-key', express.json(), (req, res) => {
  const { key } = req.body || {};
  if (!key || !/^DPRO-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}-[A-F0-9]{4}$/i.test(key))
    return res.status(400).json({ error: 'Invalid key format' });
  const licFile = require('path').join(__dirname, 'data', 'license.json');
  const fs2 = require('fs');
  fs2.writeFileSync(licFile, JSON.stringify({ key, savedAt: new Date().toISOString() }, null, 2));
  checkLicense().then(s => res.json(s)).catch(err => res.status(500).json({ error: err.message }));
});

app.get('/activate', (_req, res) => res.sendFile(require('path').join(__dirname, 'public', 'activate.html')));

// ─── Public routes (no auth) ──────────────────────────────────────────────────
const authRouter = require('./routes/auth');
app.use('/api/auth', authRouter);

// ─── Protected API routes ─────────────────────────────────────────────────────
const apiRouter = require('./routes/api');
app.use('/api', requireAuth, licenseMiddleware, apiRouter);

// ─── Page routes ─────────────────────────────────────────────────────────────
app.get('/', (_req, res) => res.sendFile(path.join(__dirname, 'public', 'landing.html')));
app.get('/login', (_req, res) => res.sendFile(path.join(__dirname, 'public', 'login.html')));
app.get('/app', (_req, res) => res.sendFile(path.join(__dirname, 'public', 'index.html')));

// ─── Download installer ───────────────────────────────────────────────────────
const distDir = path.join(__dirname, 'dist');
app.get('/download/:file', (req, res) => {
  const clean = path.basename(req.params.file); // no traversal
  const full  = path.join(distDir, clean);
  if (!fs.existsSync(full)) return res.status(404).send('File not found');
  res.download(full);
});

// ─── SPA fallback (app shell only) ────────────────────────────────────────────
app.get('/app/*', (_req, res) => res.sendFile(path.join(__dirname, 'public', 'index.html')));
app.get('*', (_req, res) => res.sendFile(path.join(__dirname, 'public', 'landing.html')));

// ─── Bootstrap data directories ──────────────────────────────────────────────
const dirs = [
  path.join(__dirname, 'data'),
  path.join(__dirname, 'uploads'),
  path.join(__dirname, 'backups'),
  path.join(__dirname, 'logs'),
];
dirs.forEach(d => fs.mkdirSync(d, { recursive: true }));

const configPath = path.join(__dirname, 'data', 'config.json');
const deploymentsPath = path.join(__dirname, 'data', 'deployments.json');
const activityPath = path.join(__dirname, 'data', 'activity.json');

if (!fs.existsSync(configPath)) {
  fs.writeFileSync(configPath, JSON.stringify({
    sites: [],
    settings: {
      maxVersions: 10,
      autoBackup: true,
      iisResetOnDeploy: false,
      stopPoolBeforeDeploy: true,
      backupBasePath: path.join(__dirname, 'backups'),
    },
  }, null, 2));
}
if (!fs.existsSync(deploymentsPath)) {
  fs.writeFileSync(deploymentsPath, JSON.stringify([], null, 2));
}
if (!fs.existsSync(activityPath)) {
  fs.writeFileSync(activityPath, JSON.stringify([], null, 2));
}

// ─── Start ───────────────────────────────────────────────────────────────────
const PORT = process.env.PORT || 7070;
server.listen(PORT, () => {
  console.log(`\n  ╔════════════════════════════════════════╗`);
  console.log(`  ║   DeployPro  – Enterprise IIS Pipeline ║`);
  console.log(`  ╚════════════════════════════════════════╝`);
  console.log(`\n  ► http://localhost:${PORT}`);
  console.log(`  ► Run as Administrator for IIS management\n`);
});
