/**
 * Live 邀請網絡 — 對齊 apps/backend /api/v1/invite/*
 */
import type {
  InviteMemberBrief,
  InviteTreeNode,
  MyInviteNetwork,
  Role,
  MemberStatus,
} from "../../domain/types";
import type { InviteRepo } from "../repos";
import { apiRequest } from "./http";

function uidToString(uid: unknown): string {
  if (typeof uid === "number" || typeof uid === "bigint") return String(uid);
  if (typeof uid === "string") return uid;
  return String(uid ?? "");
}

function mapBrief(raw: Record<string, unknown>): InviteMemberBrief {
  const parentRaw = raw.parent_uid;
  return {
    uid: uidToString(raw.uid),
    email: String(raw.email ?? ""),
    display_name: String(raw.display_name ?? ""),
    invite_code: String(raw.invite_code ?? "—"),
    parent_uid:
      parentRaw === null || parentRaw === undefined || parentRaw === 0 || parentRaw === "0"
        ? null
        : uidToString(parentRaw),
    roles: (Array.isArray(raw.roles) ? raw.roles : ["member"]) as Role[],
    status: (raw.status === "suspended" ? "suspended" : "active") as MemberStatus,
    downline_count: Number(raw.downline_count ?? 0),
    total_downline_count: Number(raw.total_downline_count ?? 0),
    depth: Number(raw.depth ?? 0),
    joined_at: Number(raw.joined_at ?? 0),
    avatar_url:
      raw.avatar_url != null && String(raw.avatar_url).trim() !== ""
        ? String(raw.avatar_url)
        : null,
  };
}

function mapTree(raw: Record<string, unknown>): InviteTreeNode {
  const childrenRaw = Array.isArray(raw.children) ? raw.children : [];
  return {
    ...mapBrief(raw),
    children: childrenRaw.map((c) => mapTree(c as Record<string, unknown>)),
  };
}

function mapNetwork(raw: Record<string, unknown>): MyInviteNetwork {
  const me = mapBrief((raw.me || {}) as Record<string, unknown>);
  const uplineRaw = raw.upline as Record<string, unknown> | null | undefined;
  const downRaw = Array.isArray(raw.downlines) ? raw.downlines : [];
  const rewardsRaw = raw.rewards as Record<string, unknown> | null | undefined;
  let rewards: MyInviteNetwork["rewards"] = null;
  if (rewardsRaw) {
    const recentRaw = Array.isArray(rewardsRaw.recent) ? rewardsRaw.recent : [];
    rewards = {
      total_points: Number(rewardsRaw.total_points ?? 0),
      month_points: Number(rewardsRaw.month_points ?? 0),
      month_cap: Number(rewardsRaw.month_cap ?? 0),
      recent: recentRaw.map((r) => {
        const row = r as Record<string, unknown>;
        return {
          id: String(row.id ?? ""),
          invitee_uid: uidToString(row.invitee_uid),
          plan_id: String(row.plan_id ?? ""),
          points: Number(row.points ?? 0),
          status: String(row.status ?? ""),
          created_at: Number(row.created_at ?? 0),
        };
      }),
    };
  }
  return {
    me,
    upline: uplineRaw ? mapBrief(uplineRaw) : null,
    downlines: downRaw.map((d) => mapBrief(d as Record<string, unknown>)),
    total_downline_count: Number(raw.total_downline_count ?? me.total_downline_count ?? 0),
    rewards,
  };
}

export function createLiveInviteRepo(): InviteRepo {
  return {
    async getMyNetwork() {
      const data = await apiRequest<Record<string, unknown>>("/api/v1/invite/me");
      return mapNetwork(data);
    },
    async applyInviteCode(code) {
      const data = await apiRequest<Record<string, unknown>>("/api/v1/invite/apply", {
        method: "POST",
        body: { code },
      });
      return mapNetwork(data);
    },
    async getTree() {
      const data = await apiRequest<{ list?: Record<string, unknown>[] }>("/api/v1/invite/tree");
      return (data.list ?? []).map((n) => mapTree(n));
    },
    async moveMember(uid, newParentUid) {
      const body: { uid: number; parent_uid?: number } = {
        uid: Number(uid),
      };
      if (newParentUid != null && String(newParentUid).trim() !== "") {
        body.parent_uid = Number(newParentUid);
      } else {
        body.parent_uid = 0;
      }
      const data = await apiRequest<Record<string, unknown>>("/api/v1/invite/move", {
        method: "POST",
        body,
      });
      return mapBrief(data);
    },
    async listParentCandidates(excludeSubtreeRootUid) {
      const q =
        excludeSubtreeRootUid && String(excludeSubtreeRootUid).trim()
          ? `?exclude_subtree_root_uid=${encodeURIComponent(String(excludeSubtreeRootUid))}`
          : "";
      const data = await apiRequest<{ list?: Record<string, unknown>[] }>(
        `/api/v1/invite/parent-candidates${q}`,
      );
      return (data.list ?? []).map((b) => mapBrief(b));
    },
  };
}
