/**
 * REST API routes.
 *
 * Public (requires API token OR session):
 *   POST   /api/sms/send
 *   GET    /api/sms/messages
 *   GET    /api/sms/messages/sent
 *   GET    /api/sms/messages/received
 *
 * Admin-only (requires session):
 *   GET    /api/config
 *   PUT    /api/config
 *   POST   /api/config/test
 *   GET    /api/tokens
 *   POST   /api/tokens
 *   DELETE /api/tokens/:id
 *   PATCH  /api/tokens/:id
 *   GET    /api/webhooks
 *   POST   /api/webhooks
 *   PUT    /api/webhooks/:id
 *   DELETE /api/webhooks/:id
 *   GET    /api/stats
 *   GET    /api/log-level
 *   PUT    /api/log-level
 *
 * Auth:
 *   POST   /api/auth/login
 *   POST   /api/auth/logout
 *   GET    /api/auth/me
 *   PUT    /api/auth/password
 */

const router = require('express').Router();
const bcrypt = require('bcryptjs');

const {
  getAdmin, updateAdminPassword, getAllConfig, getConfig, setConfig,
  createToken, listTokens, deleteToken, toggleToken,
  listWebhooks, createWebhook, updateWebhook, deleteWebhook,
  saveMessage, updateMessageStatus, listMessages, getMessageStats,
} = require('../db');

const teltonika = require('../teltonika');
const { dispatchWebhooks } = require('../webhookDispatcher');
const { requireApiToken, requireSession, requireAny } = require('../middleware/auth');
const { triggerPoll } = require('../poller');
const log = require('../logger');

// ── Auth ──────────────────────────────────────────────────────────────────────

router.post('/auth/login', (req, res) => {
  const { username, password } = req.body || {};
  if (!username || !password) {
    return res.status(400).json({ error: 'username and password required' });
  }
  const admin = getAdmin(username);
  if (!admin || !bcrypt.compareSync(password, admin.password)) {
    log.warn('Auth', `Failed login attempt for username "${username}"`);
    return res.status(401).json({ error: 'Invalid credentials' });
  }
  req.session.admin = { id: admin.id, username: admin.username };
  log.info('Auth', `User "${username}" logged in`);
  res.json({ success: true, username: admin.username });
});

router.post('/auth/logout', (req, res) => {
  log.info('Auth', `User "${req.session?.admin?.username}" logged out`);
  req.session.destroy();
  res.json({ success: true });
});

router.get('/auth/me', (req, res) => {
  if (req.session?.admin) {
    return res.json({ authenticated: true, username: req.session.admin.username });
  }
  res.json({ authenticated: false });
});

router.put('/auth/password', requireSession, (req, res) => {
  const { currentPassword, newPassword } = req.body || {};
  if (!currentPassword || !newPassword) {
    return res.status(400).json({ error: 'currentPassword and newPassword required' });
  }
  if (newPassword.length < 6) {
    return res.status(400).json({ error: 'New password must be at least 6 characters' });
  }
  const admin = getAdmin(req.session.admin.username);
  if (!bcrypt.compareSync(currentPassword, admin.password)) {
    return res.status(401).json({ error: 'Current password incorrect' });
  }
  updateAdminPassword(req.session.admin.username, newPassword);
  log.info('Auth', `Password changed for user "${req.session.admin.username}"`);
  res.json({ success: true });
});

// ── Config ────────────────────────────────────────────────────────────────────

router.get('/config', requireSession, (req, res) => {
  const cfg = getAllConfig();
  // Don't expose raw password to frontend
  const safe = { ...cfg, device_password: cfg.device_password ? '••••••••' : '' };
  res.json(safe);
});

router.put('/config', requireSession, (req, res) => {
  const allowed = ['device_ip', 'device_username', 'device_modem', 'poll_interval'];
  for (const [key, value] of Object.entries(req.body || {})) {
    if (allowed.includes(key)) setConfig(key, value);
  }
  // Password only updated if not the placeholder
  if (req.body.device_password && req.body.device_password !== '••••••••') {
    setConfig('device_password', req.body.device_password);
  }
  log.info('Config', 'Device configuration updated');
  res.json({ success: true });
});

router.post('/config/test', requireSession, async (req, res) => {
  log.info('Config', 'Testing device connection…');
  const result = await teltonika.testConnection();
  log.info('Config', `Connection test result: ${result.success ? 'OK' : result.error}`);
  res.json(result);
});

// ── Log level ─────────────────────────────────────────────────────────────────

router.get('/log-level', requireSession, (req, res) => {
  res.json({ level: log.getLevel() });
});

router.put('/log-level', requireSession, (req, res) => {
  const { level } = req.body || {};
  const valid = ['ERROR', 'WARNING', 'INFO', 'DEBUG'];
  if (!level || !valid.includes(level.toUpperCase())) {
    return res.status(400).json({ error: `level must be one of: ${valid.join(', ')}` });
  }
  log.setLevel(level);
  log.info('Config', `Log level changed to ${log.getLevel()}`);
  res.json({ level: log.getLevel() });
});

// ── Stats ─────────────────────────────────────────────────────────────────────

router.get('/stats', requireSession, (req, res) => {
  res.json(getMessageStats());
});

// ── API Tokens ─────────────────────────────────────────────────────────────────

router.get('/tokens', requireSession, (req, res) => {
  res.json(listTokens());
});

router.post('/tokens', requireSession, (req, res) => {
  const { name } = req.body || {};
  if (!name) return res.status(400).json({ error: 'name required' });
  const token = createToken(name);
  log.info('Tokens', `Created API token "${name}"`);
  res.status(201).json(token);
});

router.delete('/tokens/:id', requireSession, (req, res) => {
  deleteToken(req.params.id);
  log.info('Tokens', `Deleted API token id=${req.params.id}`);
  res.json({ success: true });
});

router.patch('/tokens/:id', requireSession, (req, res) => {
  const { active } = req.body || {};
  if (active === undefined) return res.status(400).json({ error: 'active required' });
  toggleToken(req.params.id, active);
  log.info('Tokens', `Token id=${req.params.id} set active=${active}`);
  res.json({ success: true });
});

// ── Webhooks ──────────────────────────────────────────────────────────────────

router.get('/webhooks', requireSession, (req, res) => {
  res.json(listWebhooks());
});

router.post('/webhooks', requireSession, (req, res) => {
  const { name, phone_number, url, method, headers, events } = req.body || {};
  if (!name || !url) return res.status(400).json({ error: 'name and url required' });
  const hook = createWebhook({ name, phone_number, url, method, headers, events });
  log.info('Webhooks', `Created webhook "${name}" → ${url}`);
  res.status(201).json(hook);
});

router.put('/webhooks/:id', requireSession, (req, res) => {
  const hook = updateWebhook(req.params.id, req.body);
  if (!hook) return res.status(404).json({ error: 'Webhook not found' });
  log.debug('Webhooks', `Updated webhook id=${req.params.id}`);
  res.json(hook);
});

router.delete('/webhooks/:id', requireSession, (req, res) => {
  deleteWebhook(req.params.id);
  log.info('Webhooks', `Deleted webhook id=${req.params.id}`);
  res.json({ success: true });
});

// ── SMS ───────────────────────────────────────────────────────────────────────

router.post('/sms/send', requireAny, async (req, res) => {
  const { number, message } = req.body || {};
  if (!number || !message) {
    return res.status(400).json({ error: 'number and message required' });
  }

  // Save as pending immediately
  const saved = saveMessage({
    direction:    'sent',
    phone_number: number,
    message,
    status:       'pending',
  });

  try {
    const result = await teltonika.sendSMS(number, message);
    updateMessageStatus(saved.id, 'sent');

    // Dispatch webhooks for sent event
    dispatchWebhooks('sent', { ...saved, status: 'sent' }).catch(() => {});

    res.json({ success: true, message_id: saved.id, device_response: result });
  } catch (err) {
    updateMessageStatus(saved.id, 'failed');
    log.error('API', `Send SMS to ${number} failed:`, err.message);
    res.status(502).json({ error: 'Failed to send SMS', detail: err.message });
  }
});

router.get('/sms/messages', requireAny, (req, res) => {
  const { direction, limit, offset, phone } = req.query;
  const messages = listMessages({
    direction,
    phone_number: phone,
    limit:  parseInt(limit  || '100', 10),
    offset: parseInt(offset || '0',   10),
  });
  log.debug('API', `GET /sms/messages returned ${messages.length} record(s)`);
  res.json(messages);
});

router.get('/sms/messages/sent', requireAny, (req, res) => {
  const { limit, offset, phone } = req.query;
  res.json(listMessages({
    direction:    'sent',
    phone_number: phone,
    limit:  parseInt(limit  || '100', 10),
    offset: parseInt(offset || '0',   10),
  }));
});

router.get('/sms/messages/received', requireAny, (req, res) => {
  const { limit, offset, phone } = req.query;
  res.json(listMessages({
    direction:    'received',
    phone_number: phone,
    limit:  parseInt(limit  || '100', 10),
    offset: parseInt(offset || '0',   10),
  }));
});

router.post('/sms/poll', requireSession, async (req, res) => {
  try {
    await triggerPoll();
    res.json({ success: true });
  } catch (err) {
    log.error('API', 'Manual poll failed:', err.message);
    res.status(502).json({ error: err.message });
  }
});

module.exports = router;
