import type { NotificationDto, NotificationPreferencesDto } from "./dtos.js";
import { MOCK_NOTIFICATIONS, MOCK_NOTIFICATION_PREFS } from "./mock-data.js";
import { logger } from "../shared/observability/logger.js";
import { callWithMetrics } from "./grpc/call-with-metrics.js";
import { env } from "../config/env.js";

/**
 * msg 服务客户端接口（对齐 02-architecture-design.md §3.2）。
 *
 * 覆盖：
 * - listNotifications：家长通知列表
 * - markAsRead：标记已读
 * - getNotificationPreferences：通知偏好查询
 * - updateNotificationPreferences：通知偏好更新
 *
 * 注意：msg.proto 当前 Notification 缺 child_id 字段（ISSUE-007），
 * NotificationPreferences RPC 也未定义，Mock 实现返回完整结构。
 * gRPC 实现在 proto 补全后对齐。
 */
export interface MsgClient {
  listNotifications(
    parentId: string,
    unreadOnly?: boolean,
  ): Promise<NotificationDto[]>;
  markAsRead(notificationId: string): Promise<void>;
  getNotificationPreferences(
    parentId: string,
  ): Promise<NotificationPreferencesDto>;
  updateNotificationPreferences(
    parentId: string,
    prefs: NotificationPreferencesDto,
  ): Promise<NotificationPreferencesDto>;
}

// === Mock 实现（DEV_MODE=true） ===

export class MockMsgClient implements MsgClient {
  async listNotifications(
    parentId: string,
    unreadOnly = false,
  ): Promise<NotificationDto[]> {
    const all = MOCK_NOTIFICATIONS[parentId] ?? [];
    return unreadOnly ? all.filter((n) => !n.isRead) : all;
  }

  async markAsRead(notificationId: string): Promise<void> {
    for (const parentId of Object.keys(MOCK_NOTIFICATIONS)) {
      const list = MOCK_NOTIFICATIONS[parentId];
      if (!list) continue;
      const idx = list.findIndex((n) => n.id === notificationId);
      const target = list[idx];
      if (idx >= 0 && target) {
        list[idx] = { ...target, isRead: true };
        return;
      }
    }
  }

  async getNotificationPreferences(
    parentId: string,
  ): Promise<NotificationPreferencesDto> {
    return (
      MOCK_NOTIFICATION_PREFS[parentId] ?? {
        parentId,
        channels: ["APP"],
        eventTypes: {
          gradeReleased: true,
          homeworkGraded: true,
          examPublished: true,
          attendanceAlert: true,
          schoolAnnouncement: true,
        },
      }
    );
  }

  async updateNotificationPreferences(
    parentId: string,
    prefs: NotificationPreferencesDto,
  ): Promise<NotificationPreferencesDto> {
    MOCK_NOTIFICATION_PREFS[parentId] = { ...prefs, parentId };
    return MOCK_NOTIFICATION_PREFS[parentId];
  }
}

// === gRPC 实现（DEV_MODE=false） ===

interface GrpcListNotificationsResponse {
  notifications: GrpcNotification[];
}

interface GrpcNotification {
  id: string;
  userId: string;
  type: string;
  title: string;
  content: string;
  channel: string;
  isRead: boolean;
  createdAt: number;
}

/**
 * gRPC msg 客户端。
 *
 * 注意：NotificationPreferences RPC 未在 msg.proto 中定义，
 * 当前 gRPC 实现回退为默认值，待 msg 服务补全 RPC 后替换。
 */
export class GrpcMsgClient implements MsgClient {
  private readonly rawClient: unknown;

  constructor(rawClient: unknown) {
    this.rawClient = rawClient;
  }

  async listNotifications(
    parentId: string,
    unreadOnly = false,
  ): Promise<NotificationDto[]> {
    const res = await callWithMetrics<
      { userId: string; onlyUnread: boolean },
      GrpcListNotificationsResponse
    >(
      this.rawClient,
      "listNotifications",
      { userId: parentId, onlyUnread: unreadOnly },
      "msg",
    );
    return (res.notifications ?? []).map((n) => this.mapNotification(n));
  }

  async markAsRead(notificationId: string): Promise<void> {
    await callWithMetrics<{ id: string }, unknown>(
      this.rawClient,
      "markAsRead",
      { id: notificationId },
      "msg",
    );
  }

  async getNotificationPreferences(
    parentId: string,
  ): Promise<NotificationPreferencesDto> {
    // TODO: msg.proto 未定义 NotificationPreferences RPC，回退默认值
    logger.warn(
      { parentId },
      "GrpcMsgClient.getNotificationPreferences: RPC not yet defined in msg.proto, returning defaults",
    );
    return {
      parentId,
      channels: ["APP"],
      eventTypes: {
        gradeReleased: true,
        homeworkGraded: true,
        examPublished: true,
        attendanceAlert: true,
        schoolAnnouncement: true,
      },
    };
  }

  async updateNotificationPreferences(
    parentId: string,
    prefs: NotificationPreferencesDto,
  ): Promise<NotificationPreferencesDto> {
    // TODO: msg.proto 未定义 UpdateNotificationPreferences RPC
    logger.warn(
      { parentId },
      "GrpcMsgClient.updateNotificationPreferences: RPC not yet defined in msg.proto, returning input as-is",
    );
    return { ...prefs, parentId };
  }

  private mapNotification(n: GrpcNotification): NotificationDto {
    return {
      id: n.id,
      userId: n.userId,
      type: n.type,
      title: n.title,
      content: n.content,
      channel: n.channel,
      isRead: n.isRead,
      // ISSUE-007: child_id 字段待 msg.proto 补全
      childId: undefined,
      createdAt: n.createdAt,
    };
  }
}

// === 工厂辅助 ===

export function createMsgClient(): MsgClient {
  if (env.DEV_MODE) {
    return new MockMsgClient();
  }
  // gRPC 实现需要 msg.proto Service 定义，在 ClientsModule 中组装
  throw new Error(
    "GrpcMsgClient must be created via ClientsModule with proto-loader",
  );
}
