import type { GraphqlContext } from "../context.js";
import type { DashboardDataType } from "../types.js";
import type { ResolverDeps } from "./index.js";
import {
  mapChild,
  mapParent,
  mapViewport,
} from "../../aggregation/response-mapper.js";
import { orchestrate } from "../../aggregation/orchestrator.js";
import { withCacheFallback } from "../../aggregation/fallback-strategy.js";
import { CacheKeys } from "../../shared/cache/cache-key.builder.js";
import { env } from "../../config/env.js";
import { logger } from "../../shared/observability/logger.js";
import type { ChildDto, UserInfoDto, ViewportDto } from "../../clients/dtos.js";

/**
 * Dashboard Query Resolver（对齐 02-architecture-design.md §1.2 + workline P4.6）。
 *
 * P4.6 增强：
 * - Redis 缓存（15s TTL，对齐 env.DASHBOARD_CACHE_TTL_SECONDS）
 * - Redis 不可用时降级为内存 LRU
 * - 使用 Orchestrator 抽象并行编排 + partial 降级标记
 *
 * P5 增强：
 * - 聚合 msg.listNotifications(unread=true) 获取 unreadNotifications 计数
 *
 * 聚合 4 个并行调用：
 * - iam.getUserInfo → parent
 * - iam.getChildrenByParent → children
 * - iam.getViewports → viewports
 * - msg.listNotifications(unread=true) → unreadNotifications
 *
 * degraded=true 当任一下游调用失败。
 */
export function buildDashboardResolver(deps: ResolverDeps) {
  return async (
    _parent: unknown,
    _args: unknown,
    ctx: GraphqlContext,
  ): Promise<DashboardDataType> => {
    const parentId = ctx.session.parentId;
    const cacheKey = CacheKeys.dashboard(parentId);

    const result = await withCacheFallback(
      cacheKey,
      () => fetchDashboard(deps, parentId),
      env.DASHBOARD_CACHE_TTL_SECONDS,
      "dashboard",
    );

    if (result.data) {
      if (result.fromCache) {
        logger.debug({ parentId }, "Dashboard cache hit");
      }
      return result.data;
    }

    // 所有降级都失败，返回最小可用数据
    logger.warn({ parentId }, "Dashboard all fallbacks exhausted");
    return {
      parent: null,
      children: [],
      viewports: [],
      unreadNotifications: 0,
      degraded: true,
    };
  };
}

/**
 * 实际聚合下游数据（Orchestrator 并行 + 降级标记）。
 */
async function fetchDashboard(
  deps: ResolverDeps,
  parentId: string,
): Promise<DashboardDataType> {
  const orchResult = await orchestrate({
    parent: deps.iamClient.getUserInfo(parentId),
    children: deps.iamClient.getChildrenByParent(parentId),
    viewports: deps.iamClient.getViewports(parentId),
    unread: deps.msgClient.listNotifications(parentId, true),
  });

  const parent = orchResult.results.parent as UserInfoDto | null;
  const children = orchResult.results.children as ChildDto[] | null;
  const viewports = orchResult.results.viewports as ViewportDto[] | null;
  const unreadList = orchResult.results.unread as unknown[] | null;

  return {
    parent: parent ? mapParent(parent) : null,
    children: children ? children.map(mapChild) : [],
    viewports: viewports ? viewports.map(mapViewport) : [],
    unreadNotifications: unreadList ? unreadList.length : 0,
    degraded: orchResult.partial,
  };
}
