const fs = require('fs');
const path = require('path');
const { readJsonFile, writeJsonFile } = require('./jsonFileStore');

const CONFIG_DIR = path.join(__dirname, '..', 'config');
const SETTINGS_FILE = path.join(CONFIG_DIR, 'admin-settings.json');

const DEFAULT_SETTINGS = {
  scheduleCron: '*/10 7-22 * * *',
  pickupFallbackCron: '0 7,12,17,22 * * *',
  pickupWindowOffsetsMinutes: [-1, -0.5, 0, 0.5, 1, 1.5],
  regularPickupRefreshCron: '0 3 * * *',
  dormantMembershipCron: '0 4 */14 * *',
  randomDelayMinSeconds: 10,
  randomDelayMaxSeconds: 120,
  initialDelayMinSeconds: 5,
  initialDelayMaxSeconds: 30,
  storeWatchCron: '*/30 * * * *',
  storeWatchInitialDelayMinSeconds: 10,
  storeWatchInitialDelayMaxSeconds: 60,
  storeWatchRequestDelayMs: 1000,
  storeWatchStatusCacheMaxAgeMinutes: 120,
  storePickupCheckDelayMs: 400,
  messageWatcherSocketEnabled: true,
  messageWatcherFallbackEnabled: true,
  messageWatcherFallbackCron: '0 6-23 * * *',
  messageWatcherDebugLogging: true,
  maintenanceModeActive: false,
  maintenanceModeAutoEnabled: true,
  maintenanceModeActivatedAt: null,
  maintenanceModeReason: '',
  maintenanceModeErrorThreshold: 8,
  maintenanceModeErrorWindowMinutes: 10,
  ignoredSlots: [
    {
      storeId: '51450',
      slotName: 'TVS',
      info: ''
    }
  ],
  notifications: {
    ntfy: {
      enabled: false,
      serverUrl: 'https://ntfy.sh',
      topicPrefix: '',
      username: '',
      password: ''
    },
    telegram: {
      enabled: false,
      botToken: '',
      chatId: ''
    }
  }
};

function ensureDir() {
  if (!fs.existsSync(CONFIG_DIR)) {
    fs.mkdirSync(CONFIG_DIR, { recursive: true });
  }
}

function sanitizeNumber(value, fallback) {
  const num = Number(value);
  if (Number.isFinite(num) && num >= 0) {
    return num;
  }
  return fallback;
}

function sanitizeNumberArray(value, fallback) {
  if (Array.isArray(value)) {
    const cleaned = value
      .map((entry) => Number(entry))
      .filter((entry) => Number.isFinite(entry));
    return cleaned.length > 0 ? cleaned : fallback;
  }
  if (typeof value === 'string') {
    const cleaned = value
      .split(',')
      .map((entry) => Number(entry.trim()))
      .filter((entry) => Number.isFinite(entry));
    return cleaned.length > 0 ? cleaned : fallback;
  }
  return fallback;
}

function sanitizeIgnoredSlots(slots = []) {
  if (!Array.isArray(slots)) {
    return DEFAULT_SETTINGS.ignoredSlots;
  }
  return slots
    .map((slot) => {
      const slotName = slot?.slotName ?? slot?.description;
      return {
        storeId: slot?.storeId ? String(slot.storeId) : '',
        slotName: slotName ? String(slotName) : '',
        info: slot?.info ? String(slot.info) : ''
      };
    })
    .filter((slot) => slot.storeId && slot.slotName);
}

function sanitizeString(value) {
  if (typeof value === 'string') {
    return value.trim();
  }
  if (value === null || value === undefined) {
    return '';
  }
  return String(value).trim();
}

function sanitizeNullableString(value, fallback = null) {
  const sanitized = sanitizeString(value);
  return sanitized || fallback;
}

function sanitizeNotifications(input = {}) {
  const defaults = DEFAULT_SETTINGS.notifications;
  return {
    ntfy: {
      enabled: !!(input?.ntfy?.enabled),
      serverUrl: sanitizeString(input?.ntfy?.serverUrl || defaults.ntfy.serverUrl),
      topicPrefix: sanitizeString(input?.ntfy?.topicPrefix || defaults.ntfy.topicPrefix),
      username: sanitizeString(input?.ntfy?.username || defaults.ntfy.username),
      password: sanitizeString(input?.ntfy?.password || defaults.ntfy.password)
    },
    telegram: {
      enabled: !!(input?.telegram?.enabled),
      botToken: sanitizeString(input?.telegram?.botToken || defaults.telegram.botToken),
      chatId: sanitizeString(input?.telegram?.chatId || defaults.telegram.chatId)
    }
  };
}

function readSettings() {
  ensureDir();
  if (!fs.existsSync(SETTINGS_FILE)) {
    writeJsonFile(SETTINGS_FILE, DEFAULT_SETTINGS, { backup: false });
    return { ...DEFAULT_SETTINGS };
  }

  try {
    const parsed = readJsonFile(
      SETTINGS_FILE,
      DEFAULT_SETTINGS,
      (value) => value && typeof value === 'object' && !Array.isArray(value)
    );
    return {
      scheduleCron: parsed.scheduleCron || DEFAULT_SETTINGS.scheduleCron,
      pickupFallbackCron: parsed.pickupFallbackCron || DEFAULT_SETTINGS.pickupFallbackCron,
      pickupWindowOffsetsMinutes: sanitizeNumberArray(
        parsed.pickupWindowOffsetsMinutes,
        DEFAULT_SETTINGS.pickupWindowOffsetsMinutes
      ),
      regularPickupRefreshCron: parsed.regularPickupRefreshCron || DEFAULT_SETTINGS.regularPickupRefreshCron,
      dormantMembershipCron: parsed.dormantMembershipCron || DEFAULT_SETTINGS.dormantMembershipCron,
      randomDelayMinSeconds: sanitizeNumber(parsed.randomDelayMinSeconds, DEFAULT_SETTINGS.randomDelayMinSeconds),
      randomDelayMaxSeconds: sanitizeNumber(parsed.randomDelayMaxSeconds, DEFAULT_SETTINGS.randomDelayMaxSeconds),
      initialDelayMinSeconds: sanitizeNumber(parsed.initialDelayMinSeconds, DEFAULT_SETTINGS.initialDelayMinSeconds),
      initialDelayMaxSeconds: sanitizeNumber(parsed.initialDelayMaxSeconds, DEFAULT_SETTINGS.initialDelayMaxSeconds),
      storeWatchCron: parsed.storeWatchCron || DEFAULT_SETTINGS.storeWatchCron,
      storeWatchInitialDelayMinSeconds: sanitizeNumber(
        parsed.storeWatchInitialDelayMinSeconds,
        DEFAULT_SETTINGS.storeWatchInitialDelayMinSeconds
      ),
      storeWatchInitialDelayMaxSeconds: sanitizeNumber(
        parsed.storeWatchInitialDelayMaxSeconds,
        DEFAULT_SETTINGS.storeWatchInitialDelayMaxSeconds
      ),
      storeWatchRequestDelayMs: sanitizeNumber(
        parsed.storeWatchRequestDelayMs,
        DEFAULT_SETTINGS.storeWatchRequestDelayMs
      ),
      storeWatchStatusCacheMaxAgeMinutes: sanitizeNumber(
        parsed.storeWatchStatusCacheMaxAgeMinutes,
        DEFAULT_SETTINGS.storeWatchStatusCacheMaxAgeMinutes
      ),
      storePickupCheckDelayMs: sanitizeNumber(
        parsed.storePickupCheckDelayMs,
        DEFAULT_SETTINGS.storePickupCheckDelayMs
      ),
      messageWatcherSocketEnabled:
        parsed.messageWatcherSocketEnabled === undefined
          ? DEFAULT_SETTINGS.messageWatcherSocketEnabled
          : !!parsed.messageWatcherSocketEnabled,
      messageWatcherFallbackEnabled:
        parsed.messageWatcherFallbackEnabled === undefined
          ? DEFAULT_SETTINGS.messageWatcherFallbackEnabled
          : !!parsed.messageWatcherFallbackEnabled,
      messageWatcherFallbackCron:
        parsed.messageWatcherFallbackCron || DEFAULT_SETTINGS.messageWatcherFallbackCron,
      messageWatcherDebugLogging:
        parsed.messageWatcherDebugLogging === undefined
          ? DEFAULT_SETTINGS.messageWatcherDebugLogging
          : !!parsed.messageWatcherDebugLogging,
      maintenanceModeActive: !!parsed.maintenanceModeActive,
      maintenanceModeAutoEnabled:
        parsed.maintenanceModeAutoEnabled === undefined
          ? DEFAULT_SETTINGS.maintenanceModeAutoEnabled
          : !!parsed.maintenanceModeAutoEnabled,
      maintenanceModeActivatedAt: sanitizeNullableString(parsed.maintenanceModeActivatedAt, null),
      maintenanceModeReason: sanitizeString(parsed.maintenanceModeReason),
      maintenanceModeErrorThreshold: sanitizeNumber(
        parsed.maintenanceModeErrorThreshold,
        DEFAULT_SETTINGS.maintenanceModeErrorThreshold
      ),
      maintenanceModeErrorWindowMinutes: sanitizeNumber(
        parsed.maintenanceModeErrorWindowMinutes,
        DEFAULT_SETTINGS.maintenanceModeErrorWindowMinutes
      ),
      ignoredSlots: sanitizeIgnoredSlots(parsed.ignoredSlots),
      notifications: sanitizeNotifications(parsed.notifications)
    };
  } catch (error) {
    console.error('Konnte Admin-Einstellungen nicht lesen:', error.message);
    return { ...DEFAULT_SETTINGS };
  }
}

function writeSettings(patch = {}) {
  const current = readSettings();
  const next = {
    scheduleCron: patch.scheduleCron || current.scheduleCron,
    pickupFallbackCron: patch.pickupFallbackCron || current.pickupFallbackCron,
    pickupWindowOffsetsMinutes: sanitizeNumberArray(
      patch.pickupWindowOffsetsMinutes,
      current.pickupWindowOffsetsMinutes
    ),
    regularPickupRefreshCron: patch.regularPickupRefreshCron || current.regularPickupRefreshCron,
    dormantMembershipCron: patch.dormantMembershipCron || current.dormantMembershipCron,
    randomDelayMinSeconds: sanitizeNumber(patch.randomDelayMinSeconds, current.randomDelayMinSeconds),
    randomDelayMaxSeconds: sanitizeNumber(patch.randomDelayMaxSeconds, current.randomDelayMaxSeconds),
    initialDelayMinSeconds: sanitizeNumber(patch.initialDelayMinSeconds, current.initialDelayMinSeconds),
    initialDelayMaxSeconds: sanitizeNumber(patch.initialDelayMaxSeconds, current.initialDelayMaxSeconds),
    storeWatchCron: patch.storeWatchCron || current.storeWatchCron,
    storeWatchInitialDelayMinSeconds: sanitizeNumber(
      patch.storeWatchInitialDelayMinSeconds,
      current.storeWatchInitialDelayMinSeconds
    ),
    storeWatchInitialDelayMaxSeconds: sanitizeNumber(
      patch.storeWatchInitialDelayMaxSeconds,
      current.storeWatchInitialDelayMaxSeconds
    ),
    storeWatchRequestDelayMs: sanitizeNumber(
      patch.storeWatchRequestDelayMs,
      current.storeWatchRequestDelayMs
    ),
    storeWatchStatusCacheMaxAgeMinutes: sanitizeNumber(
      patch.storeWatchStatusCacheMaxAgeMinutes,
      current.storeWatchStatusCacheMaxAgeMinutes
    ),
    storePickupCheckDelayMs: sanitizeNumber(
      patch.storePickupCheckDelayMs,
      current.storePickupCheckDelayMs
    ),
    messageWatcherSocketEnabled:
      patch.messageWatcherSocketEnabled === undefined
        ? current.messageWatcherSocketEnabled
        : !!patch.messageWatcherSocketEnabled,
    messageWatcherFallbackEnabled:
      patch.messageWatcherFallbackEnabled === undefined
        ? current.messageWatcherFallbackEnabled
        : !!patch.messageWatcherFallbackEnabled,
    messageWatcherFallbackCron: patch.messageWatcherFallbackCron || current.messageWatcherFallbackCron,
    messageWatcherDebugLogging:
      patch.messageWatcherDebugLogging === undefined
        ? current.messageWatcherDebugLogging
        : !!patch.messageWatcherDebugLogging,
    maintenanceModeActive:
      patch.maintenanceModeActive === undefined
        ? current.maintenanceModeActive
        : !!patch.maintenanceModeActive,
    maintenanceModeAutoEnabled:
      patch.maintenanceModeAutoEnabled === undefined
        ? current.maintenanceModeAutoEnabled
        : !!patch.maintenanceModeAutoEnabled,
    maintenanceModeActivatedAt:
      patch.maintenanceModeActivatedAt === undefined
        ? current.maintenanceModeActivatedAt
        : sanitizeNullableString(patch.maintenanceModeActivatedAt, null),
    maintenanceModeReason:
      patch.maintenanceModeReason === undefined
        ? current.maintenanceModeReason
        : sanitizeString(patch.maintenanceModeReason),
    maintenanceModeErrorThreshold: sanitizeNumber(
      patch.maintenanceModeErrorThreshold,
      current.maintenanceModeErrorThreshold
    ),
    maintenanceModeErrorWindowMinutes: sanitizeNumber(
      patch.maintenanceModeErrorWindowMinutes,
      current.maintenanceModeErrorWindowMinutes
    ),
    ignoredSlots:
      patch.ignoredSlots !== undefined
        ? sanitizeIgnoredSlots(patch.ignoredSlots)
        : current.ignoredSlots,
    notifications:
      patch.notifications !== undefined
        ? sanitizeNotifications(patch.notifications)
        : current.notifications
  };

  if (!next.maintenanceModeActive) {
    next.maintenanceModeActivatedAt = null;
    next.maintenanceModeReason = '';
  }

  ensureDir();
  writeJsonFile(SETTINGS_FILE, next);
  return next;
}

module.exports = {
  DEFAULT_SETTINGS,
  readSettings,
  writeSettings
};
