const { all, audit, now, one, parseJson, run } = require('../db');

const SOURCES = ['common', 'industry', 'business', 'custom'];

// How many asset categories reference a class. Categories link by unique asset_class_id; older
// records that only stored asset_class_number fall back to matching on the (non-unique) number.
function categoryUsage() {
  const byId = {};
  const byNumber = {};
  for (const row of all("SELECT metadata FROM reference_values WHERE type = 'category'")) {
    const meta = parseJson(row.metadata, {});
    if (meta.asset_class_id) byId[meta.asset_class_id] = (byId[meta.asset_class_id] || 0) + 1;
    else if (meta.asset_class_number) byNumber[meta.asset_class_number] = (byNumber[meta.asset_class_number] || 0) + 1;
  }
  // Class numbers are not unique (e.g. 00.12 is shared by Computers, Casinos, and a dozen others). A
  // category that only stored a number can't be pinned to one class, so the number fallback is only
  // safe when exactly one class carries that number — otherwise it would falsely flag every sharing
  // class as "assigned."
  const numberOwners = {};
  for (const row of all('SELECT class_number FROM asset_classes WHERE class_number IS NOT NULL')) {
    numberOwners[row.class_number] = (numberOwners[row.class_number] || 0) + 1;
  }
  return { byId, byNumber, numberOwners };
}

function fromRow(row, usage) {
  if (!row) return null;
  const idCount = usage.byId[row.id] || 0;
  const uniqueNumber = row.class_number && usage.numberOwners[row.class_number] === 1;
  const numberCount = uniqueNumber ? (usage.byNumber[row.class_number] || 0) : 0;
  return {
    id: row.id,
    class_number: row.class_number,
    description: row.description,
    gds: row.gds,
    ads: row.ads,
    source: row.source,
    table: row.source, // back-compat alias used by the category picker
    category_count: idCount + numberCount
  };
}

function list() {
  const usage = categoryUsage();
  return all('SELECT * FROM asset_classes ORDER BY description').map((row) => fromRow(row, usage));
}

function getClass(id) {
  return fromRow(one('SELECT * FROM asset_classes WHERE id = ?', [id]), categoryUsage());
}

function normalize(body) {
  const num = (value) => {
    if (value === '' || value === null || value === undefined) return null;
    const n = Number(value);
    return Number.isFinite(n) ? n : null;
  };
  return {
    class_number: body.class_number ? String(body.class_number).trim() : null,
    description: String(body.description || '').trim(),
    gds: num(body.gds),
    ads: num(body.ads),
    source: SOURCES.includes(body.source) ? body.source : 'custom'
  };
}

function createClass(body, userId) {
  const input = normalize(body);
  if (!input.description) throw Object.assign(new Error('A description is required'), { status: 400 });
  const ts = now();
  const result = run(
    'INSERT INTO asset_classes (class_number, description, gds, ads, source, created_at, updated_at) VALUES (?, ?, ?, ?, ?, ?, ?)',
    [input.class_number, input.description, input.gds, input.ads, input.source, ts, ts]
  );
  audit(userId, 'create', 'asset_class', result.lastInsertRowid, null, input);
  return getClass(result.lastInsertRowid);
}

function updateClass(id, body, userId) {
  const before = one('SELECT * FROM asset_classes WHERE id = ?', [id]);
  if (!before) return null;
  const input = normalize({ ...before, ...body });
  if (!input.description) throw Object.assign(new Error('A description is required'), { status: 400 });
  run(
    'UPDATE asset_classes SET class_number = ?, description = ?, gds = ?, ads = ?, source = ?, updated_at = ? WHERE id = ?',
    [input.class_number, input.description, input.gds, input.ads, input.source, now(), id]
  );
  audit(userId, 'update', 'asset_class', id, before, input);
  return getClass(id);
}

function deleteClass(id, userId) {
  const before = one('SELECT * FROM asset_classes WHERE id = ?', [id]);
  if (!before) return false;
  run('DELETE FROM asset_classes WHERE id = ?', [id]);
  audit(userId, 'delete', 'asset_class', id, before, null);
  return true;
}

module.exports = {
  SOURCES,
  createClass,
  deleteClass,
  getClass,
  list,
  updateClass
};
