// admin-bootstrap.mjs
//
// Service container for the standalone memind_adm process.
//
// Builds only the domain services the back-office routes need (user-auth, LLM
// providers, and the minimal plaza graph behind the ops console). It deliberately
// does NOT start any user-facing daemons — no thumbnail watcher, no asset-sync
// watcher, no plaza hot-score scheduler, no goosed auto-sync. Those belong to the
// public server. Side-effecting actions (e.g. push selected LLM key to goosed)
// stay behind explicit admin routes.
//
// The same factory functions imported here are the ones server.mjs uses, so the
// domain logic has a single source of truth; only the wiring differs.
import path from 'node:path';
import { createSubscriptionService } from './billing-subscription.mjs';
import { createDbPool, isDatabaseConfigured } from './db.mjs';
import { createUserAuth } from './user-auth.mjs';
import { createLlmProviderService } from './llm-providers.mjs';
import { createPlazaPostService, formatPostRow } from './plaza-posts.mjs';
import { createPlazaInteractionService } from './plaza-interactions.mjs';
import { createPlazaOpsService } from './plaza-ops.mjs';
import { createNoopPlazaRedis } from './plaza-redis.mjs';
import { ensureAlgorithmConfig, loadAlgorithmConfig } from './plaza-algorithm.mjs';
import { createWechatAdminService } from './wechat-admin.mjs';
import { createWechatMpService, loadWechatMpConfig } from './wechat-mp.mjs';

const noop = () => {};

/**
 * Build the admin service container.
 * @param {object} [env]
 * @param {string} [env.h5Root]      Repo root used for workspace path resolution.
 * @param {string} [env.usersRoot]   User workspace root.
 * @param {string} [env.apiTarget]   Goosed/relay API target.
 * @param {string} [env.apiSecret]   Goosed/relay API secret.
 * @param {number} [env.defaultSignupBalanceCents]
 * @param {boolean} [env.ensureAdminUser]  Ensure an admin account exists on boot (default true).
 * @returns {Promise<{pool, userAuth, llmProviderService, plazaPosts, plazaOps, wechatAdmin}>}
 */
export async function createAdminServices(env = {}) {
  if (!isDatabaseConfigured()) {
    throw new Error('admin-server requires a database (set DATABASE_URL or MYSQL_* env)');
  }

  const h5Root = env.h5Root ?? process.cwd();
  const usersRoot = env.usersRoot ?? process.env.H5_USERS_ROOT ?? path.join(h5Root, 'users');
  const apiTarget = env.apiTarget ?? process.env.TKMIND_API_TARGET ?? 'https://127.0.0.1:18006';
  const apiSecret = env.apiSecret ?? process.env.TKMIND_SERVER__SECRET_KEY ?? 'local-dev-secret';
  const defaultSignupBalanceCents = Number(
    env.defaultSignupBalanceCents ?? process.env.H5_SIGNUP_BALANCE_CENTS ?? 500,
  );

  const pool = createDbPool();

  // --- plaza graph (review queue, reports, featured, analytics, creators) ---
  const plazaRedis = createNoopPlazaRedis();
  await ensureAlgorithmConfig(pool);
  const algorithmConfig = await loadAlgorithmConfig(pool);

  const plazaInteractions = createPlazaInteractionService(pool, { formatPostRow, plazaRedis });

  let plazaOps = null;
  const plazaPosts = createPlazaPostService(pool, {
    loadViewerReactions: (viewerId, postIds) =>
      plazaInteractions.loadViewerReactions(viewerId, postIds),
    plazaRedis,
    algorithmConfig,
    onPostPublished: noop,
    loadFeaturedPosts: async (viewerId) => {
      if (!plazaOps) return { homepage_banner: [], trending: [], category_top: {} };
      return plazaOps.loadActiveFeaturedPosts(viewerId);
    },
  });
  plazaOps = createPlazaOpsService(pool, {
    formatPostRow,
    reviewPost: (...args) => plazaPosts.reviewPost(...args),
    invalidateFeedCaches: () => plazaRedis?.invalidateFeedCaches?.(),
  });

  // --- platform super-admin services ---
  const subscriptionService = createSubscriptionService(pool);
  const userAuth = createUserAuth(pool, {
    usersRoot,
    h5Root,
    defaultSignupBalanceCents,
    subscriptionService,
  });
  if (env.ensureAdminUser !== false) {
    await userAuth.ensureAdminUser();
  }

  const llmProviderService = createLlmProviderService(pool, { apiTarget, apiSecret });
  const wechatMpConfig = loadWechatMpConfig();
  const wechatMpService = createWechatMpService({
    config: wechatMpConfig,
    userAuth,
    apiFetch: async () => {
      throw new Error('admin bootstrap does not proxy WeChat chat sessions');
    },
  });
  userAuth.setRechargeNotifier(async ({ userId, title, body }) => {
    if (!wechatMpService?.enabled) return;
    await wechatMpService.sendTextToUser(userId, `${title}\n${body}`.trim());
  });
  const wechatAdmin = createWechatAdminService(pool, {
    config: wechatMpConfig,
    scheduleEnabled: process.env.H5_SCHEDULE_ENABLED === '1',
    reminderWorkerEnabled: process.env.H5_REMINDER_WORKER_ENABLED === '1',
    sendWechatTextToUser: wechatMpService?.enabled
      ? (userId, text) => wechatMpService.sendTextToUser(userId, text)
      : null,
  });

  return { pool, userAuth, llmProviderService, plazaPosts, plazaOps, wechatAdmin, subscriptionService };
}
