;; Sales Report Example
;; Demonstrates data wrangling with R interop and file output

(import assert :refer :all)
(import binding :refer :all)
(import control :refer :all)
(import dict :refer :all)
(import display :refer :all)
(import looping :refer :all)
(import threading :refer :all)

(define transactions
  (list
   (dict :product "beta" :region "east" :amount 120)
   (dict :product "alpha" :region "west" :amount 80)
   (dict :product "beta" :region "north" :amount 150)
   (dict :product "gamma" :region "east" :amount 60)
   (dict :product "beta" :region "west" :amount 90)
   (dict :product "alpha" :region "north" :amount 110)
   (dict :product "gamma" :region "south" :amount 50)
   (dict :product "beta" :region "south" :amount 30)))

(println "=== Sales Transactions ===")
(println transactions)

(define products (map (lambda (t) (get "product" t)) transactions))
(define regions (map (lambda (t) (get "region" t)) transactions))
(define amounts (map (lambda (t) (get "amount" t)) transactions))
(define products-vec (unlist products))
(define regions-vec (unlist regions))
(define amounts-vec (unlist amounts))

(define total-sales (reduce + amounts))
(assert-equal 690 total-sales)

(define totals-env
  (new.env :parent (emptyenv)))
(do-list (t transactions)
  (define product (get "product" t))
  (define amount (get "amount" t))
  (define has (exists product :envir totals-env :inherits #f))
  (if has
      (assign product (+ (get product totals-env #f) amount)
              totals-env)
      (assign product amount totals-env)))

(assert-equal 190 (get "alpha" totals-env #f))
(assert-equal 390 (get "beta" totals-env #f))
(assert-equal 110 (get "gamma" totals-env #f))

(define product-names (ls totals-env))
(define product-names-list (as.list product-names))
(define totals-list
  (map (lambda (name)
         (get name totals-env #f))
       product-names-list))
(define totals-vec (unlist totals-list))
(define top-index (which.max totals-vec))
;; r-call is handy for calling R operators with special names like "["
(define top-product (r-call "[" (list product-names top-index)))
(assert-equal "beta" top-product)

(define totals-by-product (list))
(do-list (name product-names-list)
  (set! totals-by-product
        (append totals-by-product
                (list (dict :product name
                            :total (get name totals-env #f))))))

(println "\n=== Summary ===")
(println (string-concat "Total sales: " total-sales))
(println (string-concat "Totals by product: " totals-by-product))
(println (string-concat "Top product: " top-product))

(define sales-df
  (data.frame :product products-vec :region regions-vec :amount amounts-vec))

(define report-path (file.path (tempdir) "sales-report.csv"))
((:: utils write.csv) sales-df report-path #f)
(assert-true (file.exists report-path))

(println "\nExample complete!")
