import { getSystemConfig } from '../admin/system-config.service';
import { getAllNotifiers, getNotifier, getAllNotifierParams, notifyWith } from './notifiers';
import { findPushUserForConfig, getPushUserByAccount } from './push-user.service';
import { getDb } from '../database/database';

type NotifyLevel = 'info' | 'warn' | 'error';

interface NotifyChannel {
  name: string;
  params: Record<string, any>;
}

// Re-export for API routes
export { getAllNotifiers, getNotifier, getAllNotifierParams };

// ======================== Global channel management ========================

let _globalChannelsCache: NotifyChannel[] | null = null;
let _configHash = '';

function getGlobalNotifyConfigs(): NotifyChannel[] {
  const raw = getSystemConfig('global_notify_config') || '{}';
  let globalConfig: any = {};
  try { globalConfig = JSON.parse(raw); } catch {}
  const channels: NotifyChannel[] = [];
  if (globalConfig.channels) {
    for (const [name, params] of Object.entries(globalConfig.channels)) {
      if (params && typeof params === 'object') {
        channels.push({ name, params: { ...(params as any), title: 'CloudSearch' } });
      }
    }
  }
  return channels;
}

function checkEventEnabled(eventName: string): boolean {
  try {
    const raw = getSystemConfig('global_notify_config') || '{}';
    let globalConfig: any = {};
    try { globalConfig = JSON.parse(raw); } catch {}
    if (globalConfig.events && globalConfig.events[`on_${eventName}`] !== undefined) {
      return globalConfig.events[`on_${eventName}`] !== false;
    }
    const val = getSystemConfig(`notify_on_${eventName}`);
    return val !== 'false' && val !== '0';
  } catch {
    return true;
  }
}

// ======================== Core send ========================

async function sendToChannels(channels: NotifyChannel[], title: string, content: string, level: NotifyLevel): Promise<void> {
  for (const ch of channels) {
    try {
      await notifyWith(ch.name, {
        ...ch.params,
        title,
        content,
        level,
      });
    } catch (err: any) {
      console.error(`[Notify] ${ch.name} error:`, err.message);
    }
  }
}

// ======================== Export API ========================

export function notify(title: string, content: string, level: NotifyLevel = 'info'): void {
  const channels = getGlobalNotifyConfigs();
  if (channels.length === 0) return;
  sendToChannels(channels, title, content, level).catch(() => {});
}

export function notifyError(title: string, detail: string): void {
  notify(title, detail, 'error');
}

export function notifyWarn(title: string, detail: string): void {
  notify(title, detail, 'warn');
}

export function notifyInfo(title: string, detail: string): void {
  notify(title, detail, 'info');
}

function applyTemplate(template: string, vars: Record<string, string>): string {
  return template.replace(/\{([^}]+)\}/g, (_, key) => vars[key] || '{' + key + '}');
}

function getEventTemplates(): Record<string, { title?: string; content: string }> {
  try {
    const raw = getSystemConfig('global_notify_config') || '{}';
    const cfg = JSON.parse(raw);
    return cfg.eventTemplates || {};
  } catch { return {}; }
}

export function notifyEvent(eventName: string, title: string, content: string, level: NotifyLevel = 'info', templateVars?: Record<string, string>): void {
  if (!checkEventEnabled(eventName)) return;
  const eventKey = 'on_' + eventName;
  const templates = getEventTemplates();
  const tmpl = templates[eventKey];
  if (tmpl && tmpl.content) {
    const vars = { ...(templateVars || {}) };
    if (!vars.content && content) vars.content = content;
    if (!vars.title && title) vars.title = title;
    title = applyTemplate(tmpl.title || title, vars);
    content = applyTemplate(tmpl.content, vars);
  }
  notify(title, content, level);
}

export function notifyConfigEvent(
  configId: number,
  eventName: string,
  title: string,
  content: string,
  level: NotifyLevel = 'info',
  templateVars?: Record<string, string>
): void {
  // Apply global template if available
  const eventKey = 'on_' + eventName;
  const templates = getEventTemplates();
  const tmpl = templates[eventKey];
  if (tmpl && tmpl.content) {
    const vars = { ...(templateVars || {}) };
    if (!vars.content && content) vars.content = content;
    if (!vars.title && title) vars.title = title;
    title = applyTemplate(tmpl.title || title, vars);
    content = applyTemplate(tmpl.content, vars);
  }

  // Find matching push user by cloud_configs.promotion_account
  const pushUser = findPushUserForConfig(configId);
  if (!pushUser) {
    notifyEvent(eventName, title, content, level);
    return;
  }

  let notifyConfig: any = {};
  try { notifyConfig = JSON.parse(pushUser.notify_config); } catch {}

  if (notifyConfig.events && notifyConfig.events[eventKey] === false) return;

  const userChannels: NotifyChannel[] = [];
  if (notifyConfig.channels) {
    for (const [name, params] of Object.entries(notifyConfig.channels)) {
      userChannels.push({ name, params: { ...(params as any), title } });
    }
  }

  if (userChannels.length > 0) {
    sendToChannels(userChannels, title, content, level).catch(() => {});
  } else {
    notifyEvent(eventName, title, content, level);
  }
}

export async function testChannel(
  channelName: string,
  account?: string,
  directParams?: Record<string, any>
): Promise<{ success: boolean; message: string }> {
  let params: Record<string, any> = {};

  if (directParams) {
    params = directParams;
  } else if (account) {
    const user = getPushUserByAccount(account);
    if (user) {
      let notifyConfig: any = {};
      try { notifyConfig = JSON.parse(user.notify_config); } catch {}
      const chParams = notifyConfig.channels?.[channelName];
      if (!chParams) return { success: false, message: 'User has not configured this channel' };
      params = chParams;
    } else {
      return { success: false, message: 'Push user not found' };
    }
  } else {
    const channels = getGlobalNotifyConfigs();
    const ch = channels.find(c => c.name === channelName);
    if (!ch) return { success: false, message: 'Channel not configured globally' };
    params = ch.params;
  }

  const result = await notifyWith(channelName, {
    ...params,
    title: '\u{1F514} CloudSearch Test',
    content: `Test message\\nChannel: ${channelName}\\nTime: ${new Date().toLocaleString('zh-CN', { timeZone: 'Asia/Shanghai' })}`,
    level: 'info',
  });
  return result;
}

export function saveConfigNotifySettings(configId: number, notify: any): void {
  try {
    const db = getDb();
    db.prepare('UPDATE cloud_configs SET notify_config = ? WHERE id = ?').run(JSON.stringify(notify), configId);
  } catch (err: any) {
    console.error('[Notify] Failed to save config notify settings:', err.message);
  }
}

function getConfigNotifySettings(configId: number): any {
  try {
    const db = getDb();
    const row = db.prepare('SELECT notify_config FROM cloud_configs WHERE id = ?').get(configId) as any;
    if (row && row.notify_config) return JSON.parse(row.notify_config);
  } catch {}
  return {};
}

export function getConfigNotifySettingsJSON(configId: number): any {
  return getConfigNotifySettings(configId);
}
