/**
 * 订阅模块通用 CRUD（与 admin 约定 POST /{model}/page|add|edit|del ，GET /{model}/detail|all）
 */
const baseModel = require("../../middleware/baseModel");
const { op } = baseModel;

function getRequestBody(ctx) {
  if (ctx.request && ctx.request.body && Object.keys(ctx.request.body).length > 0) {
    return ctx.request.body;
  }
  if (typeof ctx.getBody === "function") {
    return ctx.getBody() || {};
  }
  return {};
}

function getModel(modelName) {
  const m = baseModel[modelName];
  if (!m) {
    throw new Error(`模型不存在: ${modelName}`);
  }
  return m;
}

function normalizeForWrite(model, data, { forCreate } = {}) {
  const attrs = model.rawAttributes;
  const out = {};
  for (const k of Object.keys(data || {})) {
    if (!attrs[k]) continue;
    let v = data[k];
    if (v === "") {
      if (k === "id" && forCreate) continue;
      if (k.endsWith("_id") || k === "id") {
        v = null;
      } else if (attrs[k].allowNull) {
        v = null;
      }
    }
    if (k === "enabled_features" && typeof v === "string" && v.trim() !== "") {
      try {
        v = JSON.parse(v);
      } catch (e) {
        /* 保持原字符串，由 Sequelize 或 DB 报错 */
      }
    }
    out[k] = v;
  }
  if (forCreate && out.id !== undefined && (out.id === "" || out.id === null)) {
    delete out.id;
  }
  return out;
}

function buildSearchWhere(model, seachOption) {
  const key = seachOption && seachOption.key;
  const raw = seachOption && seachOption.value;
  if (!key || raw === undefined || raw === null) return {};
  const str = String(raw).trim();
  if (str === "") return {};

  const attr = model.rawAttributes[key];
  if (!attr) {
    return { [key]: { [op.like]: `%${str}%` } };
  }

  const typeKey = attr.type && attr.type.key;

  if (typeKey === "BOOLEAN") {
    if (str === "true" || str === "1" || str === "是") return { [key]: true };
    if (str === "false" || str === "0" || str === "否") return { [key]: false };
    return {};
  }

  if (typeKey === "ENUM") {
    return { [key]: str };
  }

  if (
    typeKey === "INTEGER" ||
    typeKey === "BIGINT" ||
    typeKey === "FLOAT" ||
    typeKey === "DOUBLE" ||
    typeKey === "DECIMAL"
  ) {
    const n = Number(str);
    if (!Number.isNaN(n)) return { [key]: n };
    return {};
  }

  if (typeKey === "DATE" || typeKey === "DATEONLY") {
    return { [key]: str };
  }

  return { [key]: { [op.like]: `%${str}%` } };
}

async function page(modelName, body) {
  const model = getModel(modelName);
  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 where = buildSearchWhere(model, seachOption);

  const { count, rows } = await model.findAndCountAll({
    where,
    offset,
    limit: pageSize,
    order: [["id", "DESC"]],
  });

  return { rows, count };
}

async function add(modelName, body) {
  const model = getModel(modelName);
  const payload = normalizeForWrite(model, body, { forCreate: true });
  const row = await model.create(payload);
  return row;
}

async function edit(modelName, body) {
  const model = getModel(modelName);
  const id = body.id;
  if (id === undefined || id === null || id === "") {
    throw new Error("缺少 id");
  }
  const payload = normalizeForWrite(model, body, { forCreate: false });
  delete payload.id;
  await model.update(payload, { where: { id } });
  return {};
}

async function del(modelName, body) {
  const model = getModel(modelName);
  const id = body.id !== undefined ? body.id : body;
  if (id === undefined || id === null || id === "") {
    throw new Error("缺少 id");
  }
  await model.destroy({ where: { id } });
  return {};
}

async function detail(modelName, query) {
  const model = getModel(modelName);
  const id = query && (query.id || query.ID);
  if (id === undefined || id === null || id === "") {
    throw new Error("缺少 id");
  }
  const row = await model.findByPk(id);
  return row;
}

async function all(modelName) {
  const model = getModel(modelName);
  const rows = await model.findAll({
    limit: 2000,
    order: [["id", "DESC"]],
  });
  return rows;
}

async function exportCsv(modelName, body) {
  const model = getModel(modelName);
  const param = body.param || body;
  const where = buildSearchWhere(model, param.seachOption || {});
  const rows = await model.findAll({
    where,
    limit: 10000,
    order: [["id", "DESC"]],
  });
  return { rows };
}

module.exports = {
  page,
  add,
  edit,
  del,
  detail,
  all,
  exportCsv,
  getRequestBody,
  buildSearchWhere,
};
