const Sequelize = require("sequelize");
const { normalize_for_write, build_search_where } = require("../utils/query_helpers");
const baseModel = require("../../middleware/baseModel");
const tokenLogic = require("../service/biz_token_logic");
const audit = require("../utils/biz_audit");
const biz_token_secret_cipher = require("../utils/biz_token_secret_cipher");

function map_tokens_for_admin_detail(token_rows) {
  return token_rows.map((t) => {
    const o = t.get ? t.get({ plain: true }) : { ...t };
    const cipher = o.secret_cipher;
    delete o.secret_cipher;
    o.plain_token = biz_token_secret_cipher.decrypt_plain_from_storage(cipher);
    return o;
  });
}

module.exports = {
  "POST /biz_user/page": async (ctx) => {
    const body = ctx.getBody();
    const param = body.param || body;
    const pageOption = param.pageOption || {};
    const seachOption = param.seachOption || {};
    const pageNum = parseInt(pageOption.page, 10) || 1;
    const pageSize = parseInt(pageOption.pageSize, 10) || 20;
    const offset = (pageNum - 1) * pageSize;
    const biz_user = baseModel.biz_user;
    const where = build_search_where(biz_user, seachOption);
    const { count, rows } = await biz_user.findAndCountAll({
      where,
      offset,
      limit: pageSize,
      order: [["id", "DESC"]],
      attributes: {
        include: [
          [
            Sequelize.literal(
              `(SELECT COUNT(*) FROM biz_api_token WHERE biz_api_token.user_id = biz_user.id)`
            ),
            "token_count",
          ],
        ],
      },
    });
    ctx.success({ rows, count });
  },
  "POST /biz_user/add": async (ctx) => {
    const body = ctx.getBody();
    const biz_user = baseModel.biz_user;
    const payload = normalize_for_write(biz_user, body, { for_create: true });
    const row = await biz_user.create(payload);
    await audit.logAudit({
      admin_user_id: audit.pickAdminId(ctx),
      biz_user_id: row.id,
      action: "biz_user.add",
      resource_type: "biz_user",
      resource_id: row.id,
      detail: { name: row.name },
    });

    const out = row.get({ plain: true });
    let plain_token = null;
    let token_warn = null;
    let token_error = null;
    const auto_token = body.auto_create_token !== false;
    if (auto_token && row.status === "active") {
      try {
        const result = await tokenLogic.createToken({
          user_id: row.id,
          token_name: body.initial_token_name || "default",
          expire_at: body.initial_token_expire_at || tokenLogic.defaultTokenExpireAt(),
        });
        await audit.logAudit({
          admin_user_id: audit.pickAdminId(ctx),
          biz_user_id: row.id,
          action: "biz_token.create",
          resource_type: "biz_api_token",
          resource_id: result.row.id,
          detail: { token_name: result.row.token_name, via: "biz_user.add" },
        });
        plain_token = result.plain_token;
        token_warn = result.warn;
      } catch (e) {
        token_error = e.message || String(e);
      }
    }

    ctx.success({
      ...out,
      plain_token,
      token_warn,
      token_error,
    });
  },
  "POST /biz_user/edit": async (ctx) => {
    const body = ctx.getBody();
    const id = body.id;
    if (id === undefined || id === null || id === "") throw new Error("缺少 id");
    const biz_user = baseModel.biz_user;
    const payload = normalize_for_write(biz_user, body, { for_create: false });
    delete payload.id;
    await biz_user.update(payload, { where: { id } });
    await audit.logAudit({
      admin_user_id: audit.pickAdminId(ctx),
      biz_user_id: body.id,
      action: "biz_user.edit",
      resource_type: "biz_user",
      resource_id: body.id,
    });
    ctx.success({});
  },
  "POST /biz_user/del": async (ctx) => {
    const body = ctx.getBody();
    const id = body.id !== undefined ? body.id : body;
    if (id === undefined || id === null || id === "") throw new Error("缺少 id");
    const biz_user = baseModel.biz_user;
    await biz_user.destroy({ where: { id } });
    await audit.logAudit({
      admin_user_id: audit.pickAdminId(ctx),
      biz_user_id: body.id,
      action: "biz_user.del",
      resource_type: "biz_user",
      resource_id: body.id,
    });
    ctx.success({});
  },
  "GET /biz_user/detail": async (ctx) => {
    const q = ctx.query || {};
    const id = q.id || q.ID;
    if (id === undefined || id === null || id === "") throw new Error("缺少 id");
    const biz_user = baseModel.biz_user;
    const user = await biz_user.findByPk(id);
    if (!user) {
      return ctx.fail("用户不存在");
    }
    const subscriptions = await baseModel.biz_subscription.findAll({
      where: { user_id: id },
      order: [["id", "DESC"]],
      limit: 10,
    });
    const tokenCount = await baseModel.biz_api_token.count({
      where: { user_id: id },
    });
    const tokens = await baseModel.biz_api_token.findAll({
      where: { user_id: id },
      order: [["id", "DESC"]],
      limit: 200,
    });
    const tokens_out = map_tokens_for_admin_detail(tokens);
    ctx.success({
      user,
      subscriptions,
      tokenCount,
      tokens: tokens_out,
    });
  },
  "GET /biz_user/all": async (ctx) => {
    const biz_user = baseModel.biz_user;
    const rows = await biz_user.findAll({
      limit: 2000,
      order: [["id", "DESC"]],
    });
    ctx.success(rows);
  },
  "POST /biz_user/disable": async (ctx) => {
    const body = ctx.getBody();
    const id = body.id;
    if (id == null) return ctx.fail("缺少 id");
    const biz_user = baseModel.biz_user;
    await biz_user.update({ status: "disabled" }, { where: { id } });
    await audit.logAudit({
      admin_user_id: audit.pickAdminId(ctx),
      biz_user_id: id,
      action: "biz_user.disable",
      resource_type: "biz_user",
      resource_id: id,
    });
    ctx.success({});
  },
  "POST /biz_user/enable": async (ctx) => {
    const body = ctx.getBody();
    const id = body.id;
    if (id == null) return ctx.fail("缺少 id");
    const biz_user = baseModel.biz_user;
    await biz_user.update({ status: "active" }, { where: { id } });
    await audit.logAudit({
      admin_user_id: audit.pickAdminId(ctx),
      biz_user_id: id,
      action: "biz_user.enable",
      resource_type: "biz_user",
      resource_id: id,
    });
    ctx.success({});
  },
  "POST /biz_user/export": async (ctx) => {
    const body = ctx.getBody();
    const param = body.param || body;
    const biz_user = baseModel.biz_user;
    const where = build_search_where(biz_user, param.seachOption || {});
    const rows = await biz_user.findAll({
      where,
      limit: 10000,
      order: [["id", "DESC"]],
    });
    ctx.success({ rows });
  },
  "POST /biz_user/revoke_all_tokens": async (ctx) => {
    const body = ctx.getBody();
    const userId = body.user_id != null ? body.user_id : body.id;
    if (userId == null) return ctx.fail("缺少 user_id");
    const n = await tokenLogic.revokeAllForUser(userId);
    await audit.logAudit({
      admin_user_id: audit.pickAdminId(ctx),
      biz_user_id: userId,
      action: "biz_token.revoke_all",
      resource_type: "biz_user",
      resource_id: userId,
      detail: { affected: n },
    });
    ctx.success({ revoked: n });
  },
};
