import {debtNames,openingMonth} from './financial-goals';
export type ProgressGoal={id:string;name:string;direction:'up'|'down';opening:number;target:number;planned:number[];due:number|null};
export type ProgressBaseline={start:string;feasible:boolean|null;goals:ProgressGoal[]};
export type ProgressData={baseline:ProgressBaseline;months:Record<string,Record<string,number>>};
const ids=['home','car','cards','savings','reserve','cashflow'];
export function monthOffset(start:string,month:string){const [y,m]=start.split('-').map(Number),[yy,mm]=month.split('-').map(Number);return (yy-y)*12+mm-m;}
export function progressBaseline(state:any):ProgressBaseline{
 const {input,active,start}=state,g=input.goals,goals:ProgressGoal[]=[];
 if(active){const balances=[input.home,input.car-active.lump,input.cards],series=balances.map(v=>[v]);
 for(const row of active.rows){for(let i=0;i<3;i++){const rate=[input.homeRate,input.carRate,input.cardsRate][i],paid=[row.homePaid,row.carPaid,row.cardsPaid][i];balances[i]=Math.max(0,balances[i]*(1+rate/12)-paid);if(balances[i]<0.005)balances[i]=0;series[i].push(balances[i]);}}
 ['home','car','cards'].forEach((id,i)=>{const opening=[input.home,input.car,input.cards][i];if(opening>0)goals.push({id,name:debtNames(g)[i],direction:'down',opening,target:0,planned:series[i],due:Math.round([g.homeYears,g.carYears,g.cardYears][i]*12)});});
 if(g.target>0)goals.push({id:'savings',name:g.goalName||'My Savings Goal',direction:'up',opening:g.invested,target:g.target,planned:[g.invested,...active.rows.map((r:any)=>r.investment)],due:Math.round((g.targetAge-g.age)*12)});
 if(g.reserve>0)goals.push({id:'reserve',name:'Emergency Cushion',direction:'up',opening:g.cash,target:g.reserve,planned:[g.cash-active.lump,...active.rows.map((r:any)=>r.cash)],due:null});
 }
 if(g.cashflowTarget>0)goals.push({id:'cashflow',name:g.cashflowWish||'Free Up Cash Flow',direction:'up',opening:g.cashflowCurrent,target:g.cashflowTarget,planned:[],due:null});
 return {start:start||openingMonth(),feasible:active?active.feasible:null,goals};
}
export function goalProgress(goal:ProgressGoal,month:number,actual?:number){const planned=goal.planned.length?goal.planned[Math.min(Math.max(0,Number.isFinite(month)?Math.floor(month):0),goal.planned.length-1)]:null;if(actual===undefined)return {planned,percent:null,status:'Not Checked In',difference:null};const distance=goal.direction==='down'?goal.opening-goal.target:goal.target-goal.opening;const moved=goal.direction==='down'?goal.opening-actual:actual-goal.opening;const reached=goal.direction==='down'?actual<=goal.target+0.01:actual+0.01>=goal.target;const percent=distance>0?Math.max(0,Math.min(100,moved/distance*100)):reached?100:0;const difference=planned===null?null:goal.direction==='down'?planned-actual:actual-planned;const status=reached?'Goal Reached':difference===null?'In Progress':Math.abs(difference)<=0.01?'On Track':difference>0?'Ahead Of Plan':'Needs Attention';return {planned,percent,status,difference};}
const validMonth=(v:unknown)=>typeof v==='string'&&/^\d{4}-(0[1-9]|1[0-2])$/.test(v);
const num=(v:unknown)=>typeof v==='number'&&Number.isFinite(v)&&v>=0;
export function validProgress(v:any){if(!v||!v.baseline||!(v.baseline.feasible===null||typeof v.baseline.feasible==='boolean')||!validMonth(v.baseline.start)||!Array.isArray(v.baseline.goals)||!v.baseline.goals.length||v.baseline.goals.length>6||!v.months||typeof v.months!=='object'||Array.isArray(v.months))return false;const goals=v.baseline.goals;if(!goals.every((g:any)=>g&&typeof g==='object'))return false;const keys=goals.map((g:any)=>g.id);if(new Set(keys).size!==keys.length)return false;if(!goals.every((g:any)=>ids.includes(g.id)&&typeof g.name==='string'&&g.name.length<=2000&&['up','down'].includes(g.direction)&&num(g.opening)&&num(g.target)&&Array.isArray(g.planned)&&g.planned.length<=721&&g.planned.every(num)&&(g.due===null||Number.isInteger(g.due)&&g.due>=0&&g.due<=720)))return false;const months=Object.entries(v.months);return months.length<=721&&months.every(([month,values]:any)=>validMonth(month)&&month>=v.baseline.start&&month<=openingMonth()&&values&&typeof values==='object'&&!Array.isArray(values)&&Object.keys(values).length===keys.length&&keys.every((id:string)=>num(values[id])));}
