// @File: src/lib/notifications.ts
// @Desc: Thin client for the notification center and AI ticket summaries.
//
// All requests go through the @metagptx/web-sdk's apiCall.invoke so we stay
// consistent with the rest of the client portal (auth headers, base URL, etc.
// are handled by the SDK automatically). We wrap every call in try/catch so
// transient backend failures never break the dashboard UI.
import { createClient } from "@metagptx/web-sdk";

const client = createClient();

export type NotificationType =
  | "ticket_new"
  | "ticket_reply"
  | "ticket_status_change"
  | string;

export interface NotificationRow {
  id: number;
  user_id?: string;
  type: NotificationType;
  ticket_id?: string | null;
  title: string;
  body?: string | null;
  data?: string | null;
  read?: boolean | null;
  created_at?: string | null;
  updated_at?: string | null;
}

export interface NotificationListResult {
  items: NotificationRow[];
  total: number;
  unread: number;
}

export interface NotificationPreferences {
  id?: number;
  ticket_reply: boolean;
  ticket_status_change: boolean;
  ticket_new: boolean;
  email: boolean;
}

export const DEFAULT_PREFS: NotificationPreferences = {
  ticket_reply: true,
  ticket_status_change: true,
  ticket_new: true,
  email: false,
};

/** Call the server-side sync endpoint that diffs WHMCS tickets into notifications. */
export async function syncTicketNotifications(): Promise<{ created: number; bootstrapped: boolean } | null> {
  try {
    const res = await client.apiCall.invoke({
      url: "/api/v1/notifications/sync-ticket-events",
      method: "POST",
      data: {},
    });
    const d = (res as any)?.data;
    if (d && typeof d === "object") {
      return {
        created: Number(d.created ?? 0) || 0,
        bootstrapped: !!d.bootstrapped,
      };
    }
    return null;
  } catch (err) {
    console.warn("[notifications] sync failed", err);
    return null;
  }
}

/** Fetch the current user's recent notifications, newest first. */
export async function listNotifications(limit = 30): Promise<NotificationListResult> {
  try {
    const res = await client.apiCall.invoke({
      url: "/api/v1/entities/notifications",
      method: "GET",
      data: {
        skip: 0,
        limit,
        order_by: "created_at",
        order: "desc",
      },
    });
    const data: any = (res as any)?.data ?? {};
    const items: NotificationRow[] = Array.isArray(data.items) ? data.items : [];
    const total = typeof data.total === "number" ? data.total : items.length;
    const unread = items.filter((i) => !i.read).length;
    return { items, total, unread };
  } catch (err) {
    console.warn("[notifications] list failed", err);
    return { items: [], total: 0, unread: 0 };
  }
}

/** Mark a single notification as read. */
export async function markNotificationRead(id: number): Promise<void> {
  try {
    await client.apiCall.invoke({
      url: `/api/v1/entities/notifications/${id}`,
      method: "PUT",
      data: { read: true },
    });
  } catch (err) {
    console.warn("[notifications] markRead failed", err);
  }
}

/** Mark every unread notification as read (best-effort, parallel). */
export async function markAllNotificationsRead(unreadIds: number[]): Promise<void> {
  if (unreadIds.length === 0) return;
  await Promise.all(unreadIds.map((id) => markNotificationRead(id)));
}

/** Load the user's notification preferences row, falling back to sane defaults. */
export async function getNotificationPreferences(): Promise<NotificationPreferences> {
  try {
    const res = await client.apiCall.invoke({
      url: "/api/v1/entities/notification_preferences",
      method: "GET",
      data: { skip: 0, limit: 1 },
    });
    const data: any = (res as any)?.data ?? {};
    const row = (Array.isArray(data.items) ? data.items : [])[0];
    if (row) {
      return {
        id: row.id,
        ticket_reply: row.ticket_reply ?? true,
        ticket_status_change: row.ticket_status_change ?? true,
        ticket_new: row.ticket_new ?? true,
        email: row.email ?? false,
      };
    }
  } catch (err) {
    console.warn("[notifications] getPrefs failed", err);
  }
  return { ...DEFAULT_PREFS };
}

/** Upsert notification preferences — create if none, else update. */
export async function saveNotificationPreferences(
  prefs: NotificationPreferences,
): Promise<NotificationPreferences> {
  const payload = {
    ticket_reply: prefs.ticket_reply,
    ticket_status_change: prefs.ticket_status_change,
    ticket_new: prefs.ticket_new,
    email: prefs.email,
  };
  try {
    if (prefs.id) {
      await client.apiCall.invoke({
        url: `/api/v1/entities/notification_preferences/${prefs.id}`,
        method: "PUT",
        data: payload,
      });
      return { ...prefs };
    }
    const res = await client.apiCall.invoke({
      url: "/api/v1/entities/notification_preferences",
      method: "POST",
      data: payload,
    });
    const created: any = (res as any)?.data ?? {};
    return { ...prefs, id: created?.id };
  } catch (err) {
    console.warn("[notifications] savePrefs failed", err);
    return prefs;
  }
}

/** Summarize a ticket thread using the server-side AI endpoint. */
export interface TicketSummary {
  ticket_id: number;
  model: string;
  cached: boolean;
  tl_dr: string;
  status: string;
  key_points: string[];
  action_items: string[];
  next_step: string;
}

export async function summarizeTicket(
  ticketId: number,
  opts: { force?: boolean } = {},
): Promise<TicketSummary | null> {
  try {
    const res = await client.apiCall.invoke({
      url: "/api/v1/ai/summarize-ticket",
      method: "POST",
      data: { ticket_id: ticketId, force: !!opts.force },
    });
    const data: any = (res as any)?.data;
    if (!data) return null;
    return {
      ticket_id: Number(data.ticket_id) || ticketId,
      model: String(data.model || ""),
      cached: !!data.cached,
      tl_dr: String(data.tl_dr || ""),
      status: String(data.status || ""),
      key_points: Array.isArray(data.key_points) ? data.key_points.map(String) : [],
      action_items: Array.isArray(data.action_items) ? data.action_items.map(String) : [],
      next_step: String(data.next_step || ""),
    };
  } catch (err) {
    console.warn("[notifications] summarize failed", err);
    return null;
  }
}