import { API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints";
import { validatePublicAppJumpParam } from "@/shared/app-jump/appJumpConfig.js";
import { externalRequest } from "./client.js";
import { asRecord, booleanValue, entityId, normalizePage, numberValue, textValue } from "./normalizers.js";
import { externalUiError } from "../i18n/errors.js";

// my-team is external-session scoped and is not part of the main-admin OpenAPI contract yet.
const EXTERNAL_ONLY_PATHS = Object.freeze({ myTeamAgencies: "/admin/my-team/agencies" });

export function listUsers(query) {
  return externalRequest(externalOperationPath(API_OPERATIONS.appListUsers), { query }).then((data) => normalizePage(data, normalizeUser));
}

export function listBannedUsers(query) {
  return externalRequest(externalOperationPath(API_OPERATIONS.appListBannedUsers), { query }).then((data) => normalizePage(data, normalizeBannedUser));
}

export function updateUser(userId, payload) {
  return externalRequest(externalOperationPath(API_OPERATIONS.appUpdateUser, { id: userId }), { body: payload, method: "PATCH" });
}

export function banUser(userId, payload) {
  return externalRequest(externalOperationPath(API_OPERATIONS.appBanUser, { id: userId }), { body: payload, method: "POST" });
}

export function unbanUser(userId, payload = {}) {
  return externalRequest(externalOperationPath(API_OPERATIONS.appUnbanUser, { id: userId }), { body: payload, method: "POST" });
}

export function updateUserLevels(userId, payload) {
  return externalRequest(externalOperationPath(API_OPERATIONS.appAdjustUserLevels, { id: userId }), { body: payload, method: "PUT" });
}

export async function grantUserVip(targetUserId, payload) {
  const [programData, levelsData] = await Promise.all([
    externalRequest(externalOperationPath(API_OPERATIONS.getVipProgram)),
    externalRequest(externalOperationPath(API_OPERATIONS.getVipConfig))
  ]);
  const programRoot = asRecord(programData);
  const program = asRecord(programRoot.config || programRoot.programConfig || programRoot.program_config || programRoot);
  const levelsRoot = asRecord(levelsData);
  const levels = Array.isArray(levelsData) ? levelsData : levelsRoot.levels || [];
  const level = Number(payload.level);

  if (program.status === "disabled") {
    throw externalUiError("errors.vipDisabled");
  }
  if (Array.isArray(levels) && levels.length && !levels.some((item) => Number(item.level) === level)) {
    throw externalUiError("errors.vipLevelInvalid");
  }

  const command = {
    commandId: payload.commandId,
    level,
    reason: payload.reason,
    targetUserId
  };
  if (program.grantMode === "trial_card" || program.grant_mode === "trial_card") {
    return externalRequest(externalOperationPath(API_OPERATIONS.grantVipTrialCard), {
      body: { ...command, durationMs: Number(payload.durationMs) },
      method: "POST"
    });
  }
  return externalRequest(externalOperationPath(API_OPERATIONS.grantVip), { body: command, method: "POST" });
}

export function listOrganizations(kind, query = {}) {
  const routes = {
    agencies: externalOperationPath(API_OPERATIONS.listAgencies),
    bds: externalOperationPath(API_OPERATIONS.listBDs),
    "bd-leaders": externalOperationPath(API_OPERATIONS.listManagers),
    hosts: externalOperationPath(API_OPERATIONS.listHosts),
    managers: externalOperationPath(API_OPERATIONS.listManagers),
    "super-admins": externalOperationPath(API_OPERATIONS.listBDLeaders),
    team: EXTERNAL_ONLY_PATHS.myTeamAgencies
  };
  if (!routes[kind]) {
    throw externalUiError("errors.organizationRoute");
  }
  const scopedQuery = kind === "super-admins" ? { ...query, status: query.status || "active" } : query;
  return externalRequest(routes[kind], { query: scopedQuery }).then((data) => {
    const page = normalizePage(data, normalizeOrganization);
    if (kind !== "team") {
      return page;
    }
    const source = asRecord(data);
    return {
      ...page,
      totalBdLeaders: numberValue(source.totalBdLeaders ?? source.total_bd_leaders),
      totalBds: numberValue(source.totalBds ?? source.total_bds),
      truncated: booleanValue(source.truncated)
    };
  });
}

export function listRooms(query) {
  return externalRequest(externalOperationPath(API_OPERATIONS.listRooms), { query }).then((data) => normalizePage(data, normalizeRoom));
}

export function updateRoom(roomId, payload) {
  return externalRequest(externalOperationPath(API_OPERATIONS.updateRoom, { room_id: roomId }), { body: buildRoomUpdatePayload(payload), method: "PATCH" });
}

export function buildRoomUpdatePayload(payload) {
  const regionText = String(payload.visibleRegionId ?? "").trim();
  const visibleRegionId = regionText ? Number(regionText) : 0;
  if (!Number.isSafeInteger(visibleRegionId) || visibleRegionId < 0) {
    throw externalUiError("errors.regionId");
  }
  return {
    coverUrl: String(payload.coverUrl || "").trim(),
    description: String(payload.description || "").trim(),
    title: String(payload.title || "").trim(),
    visibleRegionId
  };
}

export function listResources(query) {
  return externalRequest(externalOperationPath(API_OPERATIONS.listResources), { query }).then((data) => normalizePage(data, normalizeResource));
}

export function listResourceGrants(query) {
  return externalRequest(externalOperationPath(API_OPERATIONS.listResourceGrants), { query }).then((data) => normalizePage(data));
}

export async function lookupGrantTarget(userIdOrPrettyId) {
  const data = await externalRequest(externalOperationPath(API_OPERATIONS.lookupResourceGrantTarget), { query: { user_id: userIdOrPrettyId } });
  const source = asRecord(data);
  const user = asRecord(source.user || source.targetUser || source.target_user);
  return {
    id: textValue(source.targetUserId, source.target_user_id, source.userId, source.user_id, user.id, user.userId, user.user_id),
    prettyId: textValue(source.prettyId, source.pretty_id, user.prettyId, user.pretty_id, user.displayUserId, user.display_user_id),
    username: textValue(source.username, source.nickname, user.username, user.nickname)
  };
}

export function grantResource(payload) {
  return externalRequest(externalOperationPath(API_OPERATIONS.grantResource), { body: payload, method: "POST" });
}

export function grantPrettyId(payload) {
  return externalRequest(externalOperationPath(API_OPERATIONS.grantPrettyId), { body: payload, method: "POST" });
}

export function listBanners(query) {
  return externalRequest(externalOperationPath(API_OPERATIONS.listBanners), { query }).then((data) => normalizePage(data, normalizeBanner));
}

export function createBanner(payload) {
  return externalRequest(externalOperationPath(API_OPERATIONS.createBanner), { body: buildBannerPayload(payload), method: "POST" });
}

export function buildBannerPayload(payload) {
  if (!["h5", "app"].includes(payload.bannerType)) {
    throw externalUiError("errors.bannerType");
  }
  if (!["android", "ios"].includes(payload.platform)) {
    throw externalUiError("errors.bannerPlatform");
  }
  if (!["active", "disabled", "expired"].includes(payload.status)) {
    throw externalUiError("errors.bannerStatus");
  }
  const displayScopes = [...new Set((payload.displayScopes || []).filter((scope) => ["home", "room", "recharge", "me"].includes(scope)))];
  if (!displayScopes.length) {
    throw externalUiError("errors.bannerScope");
  }
  if (!payload.coverUrl) {
    throw externalUiError("errors.bannerImage");
  }
  if (payload.bannerType === "h5") {
    let target;
    try {
      target = new URL(payload.param);
    } catch {
      throw externalUiError("errors.h5Url");
    }
    if (!["http:", "https:"].includes(target.protocol)) {
      throw externalUiError("errors.h5Protocol");
    }
  }
  if (payload.bannerType === "app") {
    const validation = validatePublicAppJumpParam(payload.param);
    if (!validation.valid) {
      throw externalUiError(appJumpValidationKey(validation.message));
    }
  }
  if (displayScopes.includes("room") && !payload.roomSmallImageUrl) {
    throw externalUiError("errors.roomBannerImage");
  }
  const countryCode = String(payload.countryCode || "").trim().toUpperCase();
  if (countryCode && !/^[A-Z]{2,3}$/.test(countryCode)) {
    throw externalUiError("errors.countryCode");
  }
  const regionId = Number(payload.regionId || 0);
  if (!Number.isSafeInteger(regionId) || regionId < 0) {
    throw externalUiError("errors.bannerRegion");
  }
  const startsAtMs = Number(payload.startsAtMs || 0);
  const endsAtMs = Number(payload.endsAtMs || 0);
  if (startsAtMs > 0 && endsAtMs > 0 && startsAtMs >= endsAtMs) {
    throw externalUiError("errors.bannerSchedule");
  }

  return {
    bannerType: payload.bannerType,
    countryCode,
    coverUrl: payload.coverUrl,
    description: String(payload.description || "").trim(),
    displayScope: displayScopes[0],
    displayScopes,
    endsAtMs,
    param: String(payload.param || "").trim(),
    platform: payload.platform,
    regionId,
    roomSmallImageUrl: displayScopes.includes("room") ? payload.roomSmallImageUrl : "",
    sortOrder: Number(payload.sortOrder || 0),
    startsAtMs,
    status: payload.status
  };
}

export async function uploadExternalImage(file) {
  const body = new FormData();
  body.append("file", file);
  const data = await externalRequest(externalOperationPath(API_OPERATIONS.uploadImage), { body, method: "POST" });
  const source = asRecord(data);
  return textValue(source.url, source.fileUrl, source.file_url, asRecord(source.file).url);
}

export function normalizeUser(item) {
  const levels = asRecord(item.levels);
  const wealth = asRecord(levels.wealth);
  const charm = asRecord(levels.charm);
  const vip = asRecord(item.vip);
  const ban = asRecord(item.ban);
  return {
    avatar: textValue(item.avatar, item.avatarUrl, item.avatar_url),
    banned: booleanValue(ban.active, item.banned, item.isBanned, item.is_banned) || ["banned", "disabled"].includes(String(item.status).toLowerCase()),
    charmLevel: numberValue(item.charmLevel ?? item.charm_level ?? charm.displayLevel ?? charm.display_level ?? charm.level),
    country: textValue(item.country, item.countryCode, item.country_code),
    gender: textValue(item.gender),
    id: entityId(item),
    prettyId: textValue(item.prettyId, item.pretty_id, item.displayUserId, item.display_user_id, item.shortId, item.short_id),
    status: textValue(item.status, item.banned ? "banned" : "active"),
    username: textValue(item.username, item.nickname, item.nickName, item.name),
    vipLevel: numberValue(item.vipLevel ?? item.vip_level ?? vip.level),
    wealthLevel: numberValue(item.wealthLevel ?? item.wealth_level ?? wealth.displayLevel ?? wealth.display_level ?? wealth.level)
  };
}

export function normalizeBannedUser(item) {
  // Ban-list rows use the ban-log id as `id`; unban must always target the nested App user id instead.
  const target = asRecord(item.target || item.user || item.targetUser || item.target_user);
  const user = normalizeUser(target);
  return {
    ...user,
    banned: true,
    bannedAtMs: numberValue(item.bannedAtMs ?? item.banned_at_ms ?? item.createdAtMs ?? item.created_at_ms),
    banLogId: textValue(item.id, item.banLogId, item.ban_log_id),
    expiresAtMs: numberValue(item.expiresAtMs ?? item.expires_at_ms),
    id: textValue(target.userId, target.user_id, target.id),
    prettyId: textValue(target.displayUserId, target.display_user_id, target.prettyId, target.pretty_id),
    reason: textValue(item.reason)
  };
}

export function normalizeOrganization(item) {
  const user = asRecord(item.user || item.profile || item.manager);
  const agency = Boolean(item.agencyId ?? item.agency_id);
  return {
    avatar: textValue(agency ? item.ownerAvatar : "", agency ? item.owner_avatar : "", item.avatar, item.avatarUrl, item.avatar_url, user.avatar),
    appCode: textValue(item.appCode, item.app_code),
    country: textValue(item.regionName, item.region_name, item.country, item.countryCode, item.country_code, user.regionName, user.region_name, user.country),
    id: textValue(item.agencyId, item.agency_id, item.userId, item.user_id, item.id, entityId(user)),
    name: textValue(item.name, agency ? item.ownerUsername : "", item.displayName, item.display_name, item.username, user.username, user.name),
    parentBdUserId: textValue(item.parentBdUserId, item.parent_bd_user_id),
    prettyId: textValue(agency ? item.ownerDisplayUserId : "", agency ? item.owner_display_user_id : "", item.displayUserId, item.display_user_id, item.prettyId, item.pretty_id, user.displayUserId, user.display_user_id, user.prettyId, user.pretty_id),
    status: textValue(item.status, item.enabled === false ? "disabled" : "active"),
    username: textValue(agency ? item.ownerUsername : "", agency ? item.owner_username : "", item.username, user.username, user.nickname),
    userId: textValue(agency ? item.ownerUserId : "", agency ? item.owner_user_id : "", item.userId, item.user_id, user.userId, user.user_id)
  };
}

function normalizeRoom(item) {
  return {
    coverUrl: textValue(item.coverUrl, item.cover_url, item.backgroundUrl, item.background_url),
    description: textValue(item.description, item.introduction),
    id: entityId(item),
    ownerName: textValue(item.ownerName, item.owner_name, asRecord(item.owner).username),
    status: textValue(item.status, item.liveStatus, item.live_status),
    title: textValue(item.title, item.name, item.roomName, item.room_name),
    visibleRegionId: textValue(item.visibleRegionId, item.visible_region_id)
  };
}

function normalizeResource(item) {
  return {
    coverUrl: textValue(item.coverUrl, item.cover_url, item.iconUrl, item.icon_url),
    id: textValue(item.resourceId, item.resource_id, item.id),
    name: textValue(item.name, item.resourceName, item.resource_name, item.resourceCode, item.resource_code),
    status: textValue(item.status),
    type: textValue(item.resourceType, item.resource_type, item.type)
  };
}

function normalizeBanner(item) {
  return {
    bannerType: textValue(item.bannerType, item.banner_type, item.type),
    coverUrl: textValue(item.coverUrl, item.cover_url, item.imageUrl, item.image_url),
    createdAtMs: numberValue(item.createdAtMs ?? item.created_at_ms),
    description: textValue(item.description, item.title),
    id: textValue(item.id, item.bannerId, item.banner_id),
    platform: textValue(item.platform),
    sortOrder: numberValue(item.sortOrder ?? item.sort_order),
    status: textValue(item.status)
  };
}

function externalOperationPath(operation, params) {
  // Generated main-admin paths start with /v1; the external gateway already owns that version prefix in its base URL.
  return apiEndpointPath(operation, params).replace(/^\/v1(?=\/)/, "");
}

function appJumpValidationKey(message) {
  return {
    "APP 跳转参数必须是 JSON 对象": "errors.appParamObject",
    "APP 跳转 type 不在公共跳转方案内": "errors.appParamType",
    "Explore 游戏 H5 需要选择有效 game_code": "errors.appParamGameCode",
    "该 APP 跳转需要填写 game_id": "errors.appParamGame",
    "该 APP 跳转需要填写 room_id": "errors.appParamRoom",
    "该 APP 跳转需要填写有效 window": "errors.appParamWindow",
    "请填写 APP 跳转参数": "errors.appParamRequired"
  }[message] || "errors.appParamObject";
}
