import type {Locale} from './catalog';
import type {PlanCurrency} from './smart-investment';
import {cashWallet} from './cash-wallet';
import {decimalUnits,unitsDecimal,type DashboardData} from './dashboard';

const places:Record<PlanCurrency,number>={TMN:1,IRR:0,USDT:6};
const zero=BigInt(0),hundred=BigInt(100);

/** Keep editable decimal strings exact, including a decimal separator typed last. */
export function normalizeInvestmentAmount(value:string):string|null{
 if(typeof value!=='string'||value.length>80)return null;
 const normalized=value.replace(/[۰-۹]/g,d=>String('۰۱۲۳۴۵۶۷۸۹'.indexOf(d)))
  .replace(/[٠-٩]/g,d=>String('٠١٢٣٤٥٦٧٨٩'.indexOf(d)))
  .replace(/[,٬\s]/g,'').replace(/٫/g,'.');
 if(normalized==='')return '';
 if(!/^\d*(?:\.\d*)?$/.test(normalized))return null;
 const [whole,fraction]=normalized.split('.');
 const integer=whole.replace(/^0+(?=\d)/,'')||'0';
 return integer+(fraction===undefined?'':'.'+fraction);
}

/** Group the string directly: even balances above Number.MAX_SAFE_INTEGER stay exact. */
export function formatInvestmentAmount(raw:string,locale:Locale='fa'):string{
 const normalized=normalizeInvestmentAmount(raw);
 if(normalized===null||normalized==='')return '';
 const [whole,fraction]=normalized.split('.'),english=locale==='en';
 const grouped=whole.replace(/\B(?=(\d{3})+(?!\d))/g,english?',':'٬');
 const value=grouped+(fraction===undefined?'':(english?'.':'٫')+fraction);
 return english?value:value.replace(/\d/g,d=>(locale==='ar'?'٠١٢٣٤٥٦٧٨٩':'۰۱۲۳۴۵۶۷۸۹')[Number(d)]);
}

const validPositionDecimal=(value:unknown):value is string=>typeof value==='string'&&value.length<=80&&/^\d+(?:\.\d{1,18})?$/.test(value);

/** Available cash only; project valuations and locked funds are never a budget. */
export function investmentAvailableAmount(positions:DashboardData['positions'],currency:PlanCurrency):string|null{
 if(!Array.isArray(positions))return null;
 if(currency==='TMN'||currency==='IRR'){
  const rows=positions.filter(row=>row.project_id===null&&(row.asset_symbol==='IRR'||row.asset_symbol==='TMN'));
  if(!rows.length||rows.some(row=>!validPositionDecimal(row.quantity)||!validPositionDecimal(row.locked_quantity)))return null;
  const cash=cashWallet(rows);
  if(!cash)return null;
  return currency==='IRR'?cash.availableRial.toString():unitsDecimal(cash.availableRial,1);
 }
 if(currency!=='USDT')return null;
 const rows=positions.filter(row=>row.project_id===null&&row.asset_symbol==='USDT');
 if(!rows.length)return null;
 let available=zero;
 for(const row of rows){
  if(!validPositionDecimal(row.quantity)||!validPositionDecimal(row.locked_quantity))return null;
  const total=decimalUnits(row.quantity),locked=decimalUnits(row.locked_quantity);
  if(locked>total)return null;
  available+=total-locked;
 }
 // Ledger precision is 18 places; the planning form supports six USDT places.
 return unitsDecimal(available/(BigInt(10)**BigInt(12)),6);
}

function amountUnits(value:string,currency:PlanCurrency):bigint|null{
 const scale=places[currency],normalized=normalizeInvestmentAmount(value);
 if(scale===undefined||normalized===null||normalized==='')return null;
 const [whole,fraction='']=normalized.split('.');
 if(fraction.length>scale)return null;
 return BigInt(whole)*BigInt(10)**BigInt(scale)+BigInt(fraction.padEnd(scale,'0')||'0');
}

function percentageRatio(percent:number):{numerator:bigint;denominator:bigint}|null{
 if(!Number.isFinite(percent))return null;
 // Also support fractional percentages without multiplying currency by a float.
 const [mantissa,exponent='0']=String(Math.max(0,Math.min(100,percent))).split('e');
 const [whole,fraction='']=mantissa.split('.'),scale=fraction.length-Number(exponent);
 return {numerator:BigInt(whole+fraction)*BigInt(10)**BigInt(Math.max(0,-scale)),denominator:hundred*BigInt(10)**BigInt(Math.max(0,scale))};
}

/** A percentage of available funds, rounded down to the currency's smallest unit. */
export function percentageAmount(available:string,percent:number,currency:PlanCurrency):string{
 const amount=amountUnits(available,currency),ratio=percentageRatio(percent);
 if(amount===null||ratio===null)return '';
 return unitsDecimal(amount*ratio.numerator/ratio.denominator,places[currency]);
}

/** A bounded slider percentage; never convert the underlying balance to Number. */
export function investmentAmountPercent(amount:string,available:string,currency:PlanCurrency):number{
 const input=amountUnits(amount,currency),balance=amountUnits(available,currency);
 if(input===null||balance===null||balance<=zero)return 0;
 const percent=input*hundred/balance;
 return Number(percent>hundred?hundred:percent);
}
