export const TROY_OZ_PER_TONNE = 32150.7466;
export const LB_PER_TONNE = 2204.62;

export function defaultRecovery(commodity) {
  const c = String(commodity || '').toLowerCase();
  if (c === 'cu' || c === 'copper') return 0.85;
  if (c === 'ag' || c === 'silver') return 0.75;
  return 0.90;
}

export function defaultInSituFactor(assetStage = 'exploration') {
  const stage = String(assetStage || '').toLowerCase();
  if (stage.includes('production')) return 0.12;
  if (stage.includes('development') || stage.includes('resource')) return 0.06;
  return 0.03;
}

function finiteOrNull(value) {
  const n = Number(value);
  return Number.isFinite(n) ? n : null;
}

function round(value, digits = 2) {
  if (value == null || !Number.isFinite(value)) return null;
  const f = 10 ** digits;
  return Math.round(value * f) / f;
}

export function computeInSitu(input = {}) {
  const resourceTonnes = finiteOrNull(input.resource_tonnes);
  const gradeAu = finiteOrNull(input.grade_au_gpt ?? input.au_gpt);
  const gradeAg = finiteOrNull(input.grade_ag_gpt ?? input.ag_gpt);
  const gradeCu = finiteOrNull(input.grade_cu_pct ?? input.cu_pct);
  const recoveryAu = finiteOrNull(input.recovery_au) ?? defaultRecovery('Au');
  const recoveryAg = finiteOrNull(input.recovery_ag) ?? defaultRecovery('Ag');
  const recoveryCu = finiteOrNull(input.recovery_cu) ?? defaultRecovery('Cu');
  const priceAu = finiteOrNull(input.price_au_usd_oz);
  const priceAg = finiteOrNull(input.price_ag_usd_oz);
  const priceCu = finiteOrNull(input.price_cu_usd_lb);
  const inSituFactor = finiteOrNull(input.in_situ_factor) ?? defaultInSituFactor(input.asset_stage);

  if (resourceTonnes == null || resourceTonnes <= 0) {
    return {
      valuation_tier: 't1_in_situ',
      resource_tonnes: null,
      contained_au_oz: null,
      contained_ag_oz: null,
      contained_cu_lb: null,
      gross_metal_value_usd: null,
      in_situ_value_usd: null,
      recovery_au_used: recoveryAu,
      recovery_ag_used: recoveryAg,
      recovery_cu_used: recoveryCu,
      in_situ_factor_used: inSituFactor,
      usd_per_oz_au: null,
      usd_per_lb_cu: null,
      usd_per_tonne: null,
    };
  }

  const containedAuOz = gradeAu == null ? null : resourceTonnes * gradeAu / 1_000_000 * TROY_OZ_PER_TONNE * recoveryAu;
  const containedAgOz = gradeAg == null ? null : resourceTonnes * gradeAg / 1_000_000 * TROY_OZ_PER_TONNE * recoveryAg;
  const containedCuLb = gradeCu == null ? null : resourceTonnes * (gradeCu / 100) * LB_PER_TONNE * recoveryCu;

  const auValue = containedAuOz == null || priceAu == null ? 0 : containedAuOz * priceAu;
  const agValue = containedAgOz == null || priceAg == null ? 0 : containedAgOz * priceAg;
  const cuValue = containedCuLb == null || priceCu == null ? 0 : containedCuLb * priceCu;
  const gross = auValue + agValue + cuValue;
  const hasValue = gross > 0;
  const inSitu = hasValue ? gross * inSituFactor : null;

  return {
    valuation_tier: 't1_in_situ',
    resource_tonnes: round(resourceTonnes, 3),
    contained_au_oz: round(containedAuOz, 3),
    contained_ag_oz: round(containedAgOz, 3),
    contained_cu_lb: round(containedCuLb, 3),
    gross_metal_value_usd: hasValue ? gross : null,
    in_situ_value_usd: inSitu,
    recovery_au_used: recoveryAu,
    recovery_ag_used: recoveryAg,
    recovery_cu_used: recoveryCu,
    in_situ_factor_used: inSituFactor,
    usd_per_oz_au: round(inSitu != null && containedAuOz ? inSitu / containedAuOz : null, 3),
    usd_per_lb_cu: round(inSitu != null && containedCuLb ? inSitu / containedCuLb : null, 3),
    usd_per_tonne: round(inSitu != null ? inSitu / resourceTonnes : null, 3),
  };
}
