/**
 * Persist PO / gate / GRN line descriptions like the UI: "1.3 mm × HR × 2500 × 1250".
 * Material master `description` may stay short (e.g. "HR"); transactional lines get the full spec.
 */

const RAW_SPEC_MULT = ' × ';
const MAX_LEN = 500;

function formatRawMaterialMultiplyDisplay(text) {
  let s = String(text || '').trim();
  if (!s || s === '—') return s;
  s = s.replace(/\s*[×]\s*/g, RAW_SPEC_MULT);
  s = s.replace(/\s*\bx\b\s*/gi, RAW_SPEC_MULT);
  s = s.replace(/\s+/g, ' ').trim();
  if (s.includes('×')) {
    s = s.replace(/^([\d.]+)\s*mm\s*×/i, (_, n) => `${parseFloat(n)} mm ×`);
    return s;
  }
  const re = /^([\d.]+)\s*(mm)\s+(\S+)\s+(\d+)\s+(\d+)\s*$/i;
  const m = s.match(re);
  if (m) {
    return `${parseFloat(m[1])} mm${RAW_SPEC_MULT}${m[3]}${RAW_SPEC_MULT}${m[4]}${RAW_SPEC_MULT}${m[5]}`;
  }
  return s;
}

function buildRawMaterialSpecLine(linePayload, material) {
  if (!material) return String(linePayload?.description || '').trim() || '—';
  const desc = String(linePayload?.description || '').trim();
  const matDesc = String(material.description || '').trim();
  const richEnough =
    desc.length >= 6 &&
    /\d/.test(desc) &&
    (desc.includes('mm') ||
      desc.includes('MM') ||
      desc.includes('x') ||
      desc.includes('×') ||
      desc.includes('|'));
  if (richEnough) return desc;

  const colMn = String(material.material_number || '').trim();
  if (colMn && desc.startsWith(`${colMn} | `)) {
    const rest = desc.slice(colMn.length + 3).trim();
    if (rest) return rest;
  }

  let thStr = '';
  const thAssoc = material.materialThickness;
  if (thAssoc != null && thAssoc.thickness_value != null && thAssoc.thickness_value !== '') {
    const v = parseFloat(thAssoc.thickness_value);
    if (Number.isFinite(v)) thStr = `${parseFloat(v.toFixed(2))} mm`;
  } else if (material.thickness != null && material.thickness !== '') {
    const v = parseFloat(material.thickness);
    if (Number.isFinite(v)) thStr = `${parseFloat(v.toFixed(2))} mm`;
  }
  const grade = material.materialGrade?.grade_code || material.materialGrade?.grade_name || '';
  const lv = parseFloat(material.length);
  const wv = parseFloat(material.width);
  let L = '';
  let W = '';
  if (Number.isFinite(lv) && lv > 0) L = String(Math.round(lv));
  if (Number.isFinite(wv) && wv > 0) W = String(Math.round(wv));
  const mid = desc || matDesc || grade;
  const parts = [thStr, mid, L, W].filter(Boolean);
  if (parts.length >= 2) return parts.join(RAW_SPEC_MULT);
  return desc || matDesc || '—';
}

function isRawMaterialMasterType(material) {
  if (!material) return false;
  const t = String(material.material_type || '').toUpperCase();
  if (t === 'RAW_MATERIAL') return true;
  const code = material.materialType && String(material.materialType.type_code || '').toUpperCase();
  return code === 'RAW_MAT';
}

function hasSheetLikeDimensions(material) {
  if (!material) return false;
  let hasTh = false;
  const thAssoc = material.materialThickness;
  if (thAssoc != null && thAssoc.thickness_value != null && thAssoc.thickness_value !== '') {
    hasTh = Number.isFinite(parseFloat(thAssoc.thickness_value));
  } else if (material.thickness != null && material.thickness !== '') {
    hasTh = Number.isFinite(parseFloat(material.thickness));
  }
  if (!hasTh) return false;
  const lv = parseFloat(material.length);
  const wv = parseFloat(material.width);
  return Number.isFinite(lv) && lv > 0 && Number.isFinite(wv) && wv > 0;
}

function shouldBuildMaterialSpecLine(material) {
  return isRawMaterialMasterType(material) || hasSheetLikeDimensions(material);
}

/**
 * @param {object} linePayload - { description, material_id }
 * @param {object|null} material - Sequelize Material instance with optional associations
 * @returns {string} trimmed, max MAX_LEN
 */
function resolvePurchaseLineDescription(linePayload, material) {
  if (!material) {
    const d = String(linePayload?.description || '').trim();
    return d.slice(0, MAX_LEN);
  }
  if (!shouldBuildMaterialSpecLine(material)) {
    const d = String(linePayload?.description || '').trim();
    const out = d || String(material.description || '').trim();
    return out.slice(0, MAX_LEN);
  }
  const line = buildRawMaterialSpecLine(linePayload, material);
  const formatted = formatRawMaterialMultiplyDisplay(line);
  const out = String(formatted || '').trim();
  return out.slice(0, MAX_LEN);
}

/**
 * Load materials with thickness / grade / type for line description resolution.
 * @returns {Map<number, Model>}
 */
async function fetchMaterialsForLineDescription(db, materialIds, { transaction } = {}) {
  const ids = [...new Set((materialIds || []).map((id) => parseInt(id, 10)).filter((n) => n > 0))];
  if (ids.length === 0) return new Map();
  const rows = await db.Material.findAll({
    where: { id: ids },
    transaction,
    include: [
      {
        model: db.MaterialThickness,
        as: 'materialThickness',
        attributes: ['id', 'thickness_value', 'thickness_unit'],
        required: false,
      },
      {
        model: db.MaterialGrade,
        as: 'materialGrade',
        attributes: ['id', 'grade_code', 'grade_name'],
        required: false,
      },
      {
        model: db.MaterialType,
        as: 'materialType',
        attributes: ['id', 'type_code', 'type_name'],
        required: false,
      },
    ],
  });
  return new Map(rows.map((m) => [m.id, m]));
}

module.exports = {
  formatRawMaterialMultiplyDisplay,
  buildRawMaterialSpecLine,
  isRawMaterialMasterType,
  resolvePurchaseLineDescription,
  fetchMaterialsForLineDescription,
};
