const express = require('express');
const { validateURL, validateToken } = require('../src/security/input-validator');
const validatorLib = require('validator');
const { paginate, parsePaginationParams } = require('../src/utilities/pagination');
const { ValidationError } = require('../src/utilities/errors');
const { ok, successMessage } = require('../src/utils/responses');

/**
 * Notifications route factory
 * @param {Object} deps - Explicit dependencies
 * @param {Object} deps.notification - Notification manager
 * @param {Function} deps.asyncHandler - Async route handler wrapper
 * @param {Function} deps.ok - Success response helper
 * @returns {express.Router}
 */
module.exports = function({ notification, asyncHandler, ok }) {
  const router = express.Router();

  // GET /config — Get notification configuration (sensitive data redacted)
  router.get('/config', asyncHandler(async (req, res) => {
      const notificationConfig = notification.getConfig();
      // Return config without sensitive data
      const safeConfig = {
        enabled: notificationConfig.enabled,
        providers: {
          discord: {
            enabled: notificationConfig.providers.discord?.enabled || false,
            configured: !!notificationConfig.providers.discord?.webhookUrl
          },
          telegram: {
            enabled: notificationConfig.providers.telegram?.enabled || false,
            configured: !!(notificationConfig.providers.telegram?.botToken && notificationConfig.providers.telegram?.chatId)
          },
          ntfy: {
            enabled: notificationConfig.providers.ntfy?.enabled || false,
            configured: !!notificationConfig.providers.ntfy?.topic,
            serverUrl: notificationConfig.providers.ntfy?.serverUrl || 'https://ntfy.sh'
          },
          email: {
            enabled: notificationConfig.providers.email?.enabled || false,
            configured: !!(notificationConfig.providers.email?.host && notificationConfig.providers.email?.to),
            host: notificationConfig.providers.email?.host || '',
            from: notificationConfig.providers.email?.from || ''
          }
        },
        events: notificationConfig.events,
        healthCheck: notificationConfig.healthCheck
      };
      ok(res, { config: safeConfig });
  }, 'notifications-config-get'));

  // POST /config — Update notification configuration
  router.post('/config', asyncHandler(async (req, res) => {
      const { enabled, providers, events, healthCheck } = req.body;
      const notificationConfig = notification.getConfig();

      // Validate provider webhook URLs and tokens
      if (providers) {
        if (providers.discord?.webhookUrl) {
          try {
            validateURL(providers.discord.webhookUrl);
          } catch (validationErr) {
            throw new ValidationError('Invalid Discord webhook URL');
          }
        }
        if (providers.telegram?.botToken) {
          try {
            validateToken(providers.telegram.botToken);
          } catch (validationErr) {
            throw new ValidationError('Invalid Telegram bot token format');
          }
        }
        if (providers.ntfy?.serverUrl) {
          try {
            validateURL(providers.ntfy.serverUrl);
          } catch (validationErr) {
            throw new ValidationError('Invalid ntfy server URL');
          }
        }
        if (providers.ntfy?.topic) {
          const topicRegex = /^[a-zA-Z0-9_-]{1,64}$/;
          if (!topicRegex.test(providers.ntfy.topic)) {
            throw new ValidationError('Invalid ntfy topic (alphanumeric, hyphens, underscores only, max 64 chars)');
          }
        }
        if (providers.email?.to) {
          const emails = providers.email.to.split(',').map(e => e.trim());
          for (const email of emails) {
            if (!validatorLib.isEmail(email)) {
              throw new ValidationError(`Invalid email address: ${email}`);
            }
          }
        }
        if (providers.email?.host && typeof providers.email.host === 'string') {
          if (!validatorLib.isFQDN(providers.email.host) && !validatorLib.isIP(providers.email.host)) {
            throw new ValidationError('Invalid SMTP host');
          }
        }
      }

      // Update enabled state
      if (typeof enabled === 'boolean') {
        notificationConfig.enabled = enabled;
      }

      // Update providers (only update provided fields)
      if (providers) {
        if (providers.discord) {
          notificationConfig.providers.discord = {
            ...notificationConfig.providers.discord,
            ...providers.discord
          };
        }
        if (providers.telegram) {
          notificationConfig.providers.telegram = {
            ...notificationConfig.providers.telegram,
            ...providers.telegram
          };
        }
        if (providers.ntfy) {
          notificationConfig.providers.ntfy = {
            ...notificationConfig.providers.ntfy,
            ...providers.ntfy
          };
        }
        if (providers.email) {
          notificationConfig.providers.email = {
            ...notificationConfig.providers.email,
            ...providers.email
          };
        }
      }

      // Update events
      if (events) {
        notificationConfig.events = { ...notificationConfig.events, ...events };
      }

      // Update health check settings
      if (healthCheck) {
        const wasEnabled = notificationConfig.healthCheck?.enabled;
        notificationConfig.healthCheck = { ...notificationConfig.healthCheck, ...healthCheck };

        // Restart daemon if settings changed
        if (healthCheck.enabled !== wasEnabled || healthCheck.intervalMinutes) {
          if (notificationConfig.healthCheck.enabled) {
            notification.startHealthDaemon();
          } else {
            notification.stopHealthDaemon();
          }
        }
      }

      await notification.saveConfig();
      successMessage(res, 'Notification config updated');
  }, 'notifications-config-update'));

  // POST /test — Test notification delivery
  router.post('/test', asyncHandler(async (req, res) => {
    const { provider } = req.body;

    if (provider) {
      // Test specific provider
      let result;
      switch (provider) {
        case 'discord':
          result = await notification.sendDiscord('Test Notification', 'This is a test notification from DashCaddy.', 'info');
          break;
        case 'telegram':
          result = await notification.sendTelegram('Test Notification', 'This is a test notification from DashCaddy.', 'info');
          break;
        case 'ntfy':
          result = await notification.sendNtfy('Test Notification', 'This is a test notification from DashCaddy.', 'info');
          break;
        case 'email':
          result = await notification.sendEmail('Test Notification', 'This is a test notification from DashCaddy.', 'info');
          break;
        default:
          throw new ValidationError('Unknown provider');
      }
      // result.success reflects actual delivery; keep that semantic by using
      // res.json directly (ok() hardcodes success:true).
      res.json({ success: result.success, provider, error: result.error });
    } else {
      // Test all enabled providers
      const result = await notification.send('test', 'Test Notification', 'This is a test notification from DashCaddy.', 'info');
      ok(res, { ...result });
    }
  }, 'notifications-test'));

  // GET /history — Get notification history
  router.get('/history', asyncHandler(async (req, res) => {
    const notificationHistory = notification.getHistory();
    const paginationParams = parsePaginationParams(req.query);
    if (paginationParams) {
      const result = paginate(notificationHistory, paginationParams);
      ok(res, { history: result.data, total: notificationHistory.length, pagination: result.pagination });
    } else {
      const limit = parseInt(req.query.limit) || 50;
      ok(res, {
        history: notificationHistory.slice(0, limit),
        total: notificationHistory.length
      });
    }
  }, 'notifications-history'));

  // DELETE /history — Clear notification history
  router.delete('/history', asyncHandler(async (req, res) => {
    notification.clearHistory();
    successMessage(res, 'Notification history cleared');
  }, 'notifications-history-clear'));

  // POST /health-check — Manually trigger health check
  router.post('/health-check', asyncHandler(async (req, res) => {
    await notification.checkHealth();
    const notificationConfig = notification.getConfig();
    ok(res, {
      lastCheck: notificationConfig.healthCheck.lastCheck,
      containersMonitored: Object.keys(notification.getHealthState()).length
    });
  }, 'notifications-health-check'));

  // GET /status — Get notification system status
  router.get('/status', asyncHandler(async (req, res) => {
    const notificationConfig = notification.getConfig();
    const providers = notificationConfig.providers || {};
    
    ok(res, {
      enabled: notificationConfig.enabled,
      providers: {
        discord: providers.discord?.enabled && !!providers.discord?.webhookUrl,
        telegram: providers.telegram?.enabled && !!providers.telegram?.botToken && !!providers.telegram?.chatId,
        ntfy: providers.ntfy?.enabled && !!providers.ntfy?.topic,
        email: providers.email?.enabled && !!providers.email?.host && !!providers.email?.to
      },
      lastSent: notification.lastSent,
      healthCheck: notificationConfig.healthCheck?.enabled ? {
        enabled: true,
        lastCheck: notificationConfig.healthCheck.lastCheck,
        intervalMinutes: notificationConfig.healthCheck.intervalMinutes
      } : { enabled: false }
    });
  }, 'notifications-status'));

  // POST /send — Manual test send (used by frontend "Send Test" button)
  router.post('/send', asyncHandler(async (req, res) => {
    const { event, data, type } = req.body;

    if (!event) {
      throw new ValidationError('Event type is required');
    }

    // Use 'test' as the event for manual sends
    const result = await notification.send(event, data || {}, type || 'info');

    // result.success reflects actual per-provider delivery; ok() hardcodes true,
    // so use res.json to preserve the partial-failure semantic.
    res.json({
      success: result.success,
      event,
      results: result.results
    });
  }, 'notifications-send'));

  return router;
};
