[@@@import Currency, "currency.iml"]
[@@@import Transaction, "transaction.iml"]
[@@@import Account, "account.iml"]
[@@@import Asset, "asset.iml"]
[@@@import Liability, "liability.iml"]


(* Balance Sheet Report type *)
type balance_sheet_report = {
  total_assets: real;
  total_liabilities: real;
  net_assets: real
}

(* Ledger type containing assets and liabilities *)
type ledger = {
  assets: Account.account list;
  liabilities: Account.account list
}

(* Convert account balance to target currency *)
let convert_to_usd (cp: Currency.currency_pairs) (account: Account.account) : real option =
  let acc_currency = Account.currency account in
  let balance = Account.balance account in
  Currency.convert cp acc_currency Currency.USD balance

(* Calculate total for a list of accounts *)
let calculate_total (cp: Currency.currency_pairs) (accounts: Account.account list) : real =
  List.fold_left 
    (fun acc account ->
      match convert_to_usd cp account with
      | Some converted -> acc +. converted
      | None -> acc)
    0.0
    accounts

(* Generate balance sheet report *)
let generate_balance_sheet_report (cp: Currency.currency_pairs) (l: ledger) : balance_sheet_report =
  let total_assets = calculate_total cp l.assets in
  let total_liabilities = calculate_total cp l.liabilities in
  {
    total_assets = total_assets;
    total_liabilities = total_liabilities;
    net_assets = total_assets -. total_liabilities
  }

(* Initialize a ledger *)
let init_ledger (assets: Account.account list) (liabilities: Account.account list) : ledger =
  {
    assets = assets;
    liabilities = liabilities
  }

(* Main function demonstrating usage *)
let main () : balance_sheet_report option =
  let a = [] in
  let l = [] in

  (* Add liabilities (customer accounts from bank's perspective) *)
  let l = List.cons (Account.init_account {l|John Doe|l} {l|Savings Account|l} Currency.USD Account.ASSET {l|123456789|l} 1000.0) l in
  let l = List.cons (Account.init_account {l|Jane Doe|l} {l|Checking Account|l} Currency.USD Account.ASSET {l|987654321|l} 1500.0) l in
  let l = List.cons (Account.init_account {l|John Doe|l} {l|Savings Account|l} Currency.USD Account.ASSET {l|123456789|l} 1000.0) l in
  let l = List.cons (Account.init_account {l|Jane Doe|l} {l|Checking Account|l} Currency.USD Account.ASSET {l|987654321|l} 1500.0) l in
  let l = List.cons (Account.init_account {l|John Doe|l} {l|Savings Account|l} Currency.USD Account.ASSET {l|123456789|l} 1000.0) l in
  let l = List.cons (Account.init_account {l|Jane Doe|l} {l|Checking Account|l} Currency.USD Account.ASSET {l|987654321|l} 1500.0) l in

  (* Add assets *)
  let a = List.cons (Account.init_account {l|Jane Doe|l} {l|Checking Account|l} Currency.USD Account.ASSET {l|987654321|l} 1500.0) a in
  let a = List.cons (Account.init_account {l|John Doe|l} {l|Savings Account|l} Currency.USD Account.ASSET {l|123456789|l} 1000.0) a in
  let a = List.cons (Account.init_account {l|Jane Doe|l} {l|Checking Account|l} Currency.USD Account.ASSET {l|987654321|l} 1500.0) a in
  let a = List.cons (Account.init_account {l|John Doe|l} {l|Savings Account|l} Currency.USD Account.ASSET {l|123456789|l} 1000.0) a in
  let a = List.cons (Account.init_account {l|Jane Doe|l} {l|Checking Account|l} Currency.USD Account.ASSET {l|987654321|l} 1500.0) a in
  let a = List.cons (Account.init_account {l|John Doe|l} {l|Savings Account|l} Currency.USD Account.ASSET {l|123456789|l} 1000.0) a in

  let ledger = init_ledger a l in

  let rates = [
    ((Currency.EUR, Currency.USD), 1.1);
    ((Currency.USD, Currency.EUR), 0.9);
    ((Currency.GBP, Currency.USD), 1.3);
    ((Currency.USD, Currency.GBP), 0.77);
    ((Currency.JPY, Currency.USD), 0.009);
    ((Currency.USD, Currency.JPY), 110.0);
    ((Currency.CNY, Currency.USD), 0.15);
    ((Currency.USD, Currency.CNY), 6.5);
    ((Currency.INR, Currency.USD), 0.013);
    ((Currency.USD, Currency.INR), 75.0);
    ((Currency.AUD, Currency.USD), 0.7);
    ((Currency.USD, Currency.AUD), 1.4);
    ((Currency.CAD, Currency.USD), 0.8);
    ((Currency.USD, Currency.CAD), 1.25);
    ((Currency.CHF, Currency.USD), 1.05);
    ((Currency.USD, Currency.CHF), 0.95);
    ((Currency.NZD, Currency.USD), 0.65);
    ((Currency.USD, Currency.NZD), 1.54)
  ] in

  let cp = Currency.init_currency_pairs rates in
  Some (generate_balance_sheet_report cp ledger)
