export type NotifyEventType = 'running' | 'succeeded' | 'failed' | 'waiting_human';

export type NotifyEventSettings = Record<NotifyEventType, boolean>;

export const DEFAULT_NOTIFY_EVENTS: NotifyEventSettings = {
  running: true,
  succeeded: true,
  failed: true,
  waiting_human: true,
};

const STATUS_TO_EVENT: Record<string, NotifyEventType> = {
  running: 'running',
  succeeded: 'succeeded',
  failed: 'failed',
  aborted: 'failed',
  waiting_human: 'waiting_human',
};

export function mapStatusToEvent(status: string | undefined): NotifyEventType | null {
  if (!status) return null;
  return STATUS_TO_EVENT[status] ?? null;
}

export function shouldNotify(
  prev: string | undefined,
  curr: string,
  settings: NotifyEventSettings,
): NotifyEventType | null {
  if (prev === undefined) return null;       // initial snapshot
  if (prev === curr) return null;             // no transition
  const event = mapStatusToEvent(curr);
  if (event === null) return null;            // not a notify status
  if (!settings[event]) return null;          // disabled in settings
  return event;
}

const EVENT_META: Record<NotifyEventType, { emoji: string; label: string }> = {
  running: { emoji: '🟢', label: 'タスク開始' },
  succeeded: { emoji: '✅', label: 'タスク完了' },
  failed: { emoji: '❌', label: 'タスク失敗' },
  waiting_human: { emoji: '❓', label: '回答待ち' },
};

export interface TaskForNotification {
  id: number;
  title: string;
  pieceName: string;
}

export interface NotificationOptions {
  title: string;
  body: string;
  tag: string;
  icon: string;
  data: { taskId: number };
}

// Vite の base path に合わせた favicon URL。/ui/ サブパス配信で /favicon.ico は 404 になる。
// import.meta.env.BASE_URL は build 時に '/ui/' に解決される (vite.config.ts: base: '/ui/')。
const NOTIFICATION_ICON_URL = `${import.meta.env.BASE_URL}favicon.svg`;

export function buildNotificationOptions(
  task: TaskForNotification,
  event: NotifyEventType,
): NotificationOptions {
  const { emoji, label } = EVENT_META[event];
  return {
    title: `${emoji} ${label}: ${task.title}`,
    body: task.pieceName,
    tag: `task-${task.id}-${event}`,
    icon: NOTIFICATION_ICON_URL,
    data: { taskId: task.id },
  };
}

export class NotificationDebouncer {
  private timers = new Map<number, ReturnType<typeof setTimeout>>();
  private pendingStatus = new Map<number, string>();

  constructor(
    private debounceMs: number,
    private onFire: (taskId: number, status: string) => void,
  ) {}

  schedule(taskId: number, status: string): void {
    const existing = this.timers.get(taskId);
    if (existing) clearTimeout(existing);
    this.pendingStatus.set(taskId, status);
    const timer = setTimeout(() => {
      const finalStatus = this.pendingStatus.get(taskId);
      this.timers.delete(taskId);
      this.pendingStatus.delete(taskId);
      if (finalStatus !== undefined) this.onFire(taskId, finalStatus);
    }, this.debounceMs);
    this.timers.set(taskId, timer);
  }

  cancel(taskId: number): void {
    const existing = this.timers.get(taskId);
    if (existing) clearTimeout(existing);
    this.timers.delete(taskId);
    this.pendingStatus.delete(taskId);
  }

  clearAll(): void {
    this.timers.forEach(clearTimeout);
    this.timers.clear();
    this.pendingStatus.clear();
  }
}

export function isNotificationSupported(): boolean {
  return typeof (globalThis as any).Notification !== 'undefined';
}

export function getNotificationPermission(): NotificationPermission | 'unsupported' {
  if (!isNotificationSupported()) return 'unsupported';
  return (globalThis as any).Notification.permission as NotificationPermission;
}

export function createNotification(
  options: NotificationOptions,
  onClick: (taskId: number) => void,
): Notification | null {
  if (!isNotificationSupported()) {
    console.warn('[notifications] Notification API unsupported in this browser');
    return null;
  }
  const NotificationCtor = (globalThis as any).Notification;
  if (NotificationCtor.permission !== 'granted') {
    console.warn(`[notifications] permission not granted (current=${NotificationCtor.permission}) — silent skip`);
    return null;
  }
  try {
    const notification: Notification = new NotificationCtor(options.title, {
      body: options.body,
      tag: options.tag,
      icon: options.icon,
      data: options.data,
    });
    console.info(`[notifications] created tag=${options.tag} title=${options.title}`);
    notification.onclick = (event: Event) => {
      try {
        event.preventDefault();
        if (typeof window !== 'undefined') window.focus();
        const data = (notification.data ?? options.data) as { taskId: number };
        onClick(data.taskId);
      } catch (err) {
        console.warn('[notifications] onclick handler failed', err);
      }
    };
    return notification;
  } catch (err) {
    console.warn('[notifications] failed to create notification', err);
    return null;
  }
}

export async function requestNotificationPermission(): Promise<NotificationPermission | 'unsupported'> {
  if (!isNotificationSupported()) return 'unsupported';
  try {
    const result = await (globalThis as any).Notification.requestPermission();
    return result as NotificationPermission;
  } catch (err) {
    console.warn('[notifications] requestPermission failed', err);
    return 'denied';
  }
}
