@@ -370,3 +370,88 @@ let pretty_to_string t =
370370 | `Add -> " add"
371371 | `Remove -> " remove" ))
372372 t.resources)
373+
374+ let to_markdown_string t =
375+ let fmt v = Printf. sprintf " %s$%.2f" (if v > = 0.0 then " " else " -" ) (CCFloat. abs v) in
376+ (* Initial header *)
377+ let lines = [ " ### 💸 OpenInfraQuote Cost Estimate\n " ] in
378+ (* Price difference section *)
379+ let delta_min = t.price_diff.Oiq_range. min in
380+ let delta_max = t.price_diff.Oiq_range. max in
381+ let lines =
382+ if delta_min = 0.0 && delta_max = 0.0 then lines
383+ else
384+ lines
385+ @ [
386+ Printf. sprintf
387+ " Monthly cost is projected to **%s** by **%s - %s**\n "
388+ (if delta_max < 0.0 then " decrease" else " increase" )
389+ (fmt (CCFloat. abs delta_min))
390+ (fmt (CCFloat. abs delta_max));
391+ ]
392+ in
393+ (* Summary table *)
394+ let lines =
395+ lines
396+ @ [
397+ " \n | Monthly Estimate | Amount |" ;
398+ " |------------------|--------------------|" ;
399+ Printf. sprintf
400+ " | After changes | %s - %s |"
401+ (fmt t.price.Oiq_range. min)
402+ (fmt t.price.Oiq_range. max);
403+ Printf. sprintf
404+ " | Before changes | %s - %s |\n "
405+ (fmt t.prev_price.Oiq_range. min)
406+ (fmt t.prev_price.Oiq_range. max);
407+ ]
408+ in
409+ (* Group resources by change type *)
410+ let adds, removes, existing =
411+ CCList. fold_left
412+ (fun (a , r , e ) resource ->
413+ match resource.Resource. change with
414+ | `Add -> (resource :: a, r, e)
415+ | `Remove -> (a, resource :: r, e)
416+ | `Noop -> (a, r, resource :: e))
417+ ([] , [] , [] )
418+ t.resources
419+ in
420+ (* Helper to render a section of resources *)
421+ let render_section title resources =
422+ if CCList. is_empty resources then " "
423+ else
424+ let header = Printf. sprintf " <details>\n <summary>%s</summary>\n\n " title in
425+ let table =
426+ " | Resource | Type | Before changes | After changes |\n \
427+ |----------|------|----------------|----------------|\n "
428+ in
429+ let rows =
430+ CCString. concat
431+ " \n "
432+ (CCList. map
433+ (fun r ->
434+ let name = r.Resource. name in
435+ let typ = r.Resource. type_ in
436+ let est_min = r.Resource. price.Oiq_range. min in
437+ let est_max = r.Resource. price.Oiq_range. max in
438+ Printf. sprintf
439+ " | %s | %s | %s - %s | %s - %s |"
440+ name
441+ typ
442+ (fmt t.prev_price.Oiq_range. min)
443+ (fmt t.prev_price.Oiq_range. max)
444+ (fmt est_min)
445+ (fmt est_max))
446+ resources)
447+ in
448+ header ^ table ^ rows ^ " \n </details>\n "
449+ in
450+ CCString. concat
451+ " \n "
452+ (lines
453+ @ [
454+ render_section " 🟢 Added resources" adds;
455+ render_section " 🔴 Removed resources" removes;
456+ render_section " ⚪ Existing resources" existing;
457+ ])
0 commit comments