package net.gouline.riskybusiness;
import net.gouline.riskybusiness.data.ParsableParser;
import net.gouline.riskybusiness.model.Customer;
import net.gouline.riskybusiness.model.SettledBet;
import net.gouline.riskybusiness.model.UnsettledBet;
import java.io.FileReader;
import java.io.IOException;
import java.io.Reader;
import java.text.DecimalFormat;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
 * Evaluator of risk for bets.
 *
 * @author Mike Gouline
 */
public class RiskEvaluator {
  public enum RiskType {
    SUCCESS_RATE,
    STAKE_AVERAGE,
    STAKE_AVERAGE_HIGH,
    STAKE_AMOUNT
  }
  private ParsableParser<SettledBet> settledBetParser;
  private ParsableParser<UnsettledBet> unsettledBetParser;
  public RiskEvaluator() {
    settledBetParser = new ParsableParser<SettledBet>() {
      @Override
      protected SettledBet newInstance() {
        return new SettledBet();
      }
    };
    unsettledBetParser = new ParsableParser<UnsettledBet>() {
      @Override
      protected UnsettledBet newInstance() {
        return new UnsettledBet();
      }
    };
  }
  public List<UnsettledBet> evaluate(String settledFilename, String unsettledFilename) throws IOException {
    return evaluate(new FileReader(settledFilename), new FileReader(unsettledFilename));
  }
  /**
   * Evaluates settled bets and assigns risk to unsettled bets.
   *
   * @param settledReader   Reader of settled CSV data.
   * @param unsettledReader Reader of unsettled CSV data.
   * @return List of unsettled bets with risk assignment.
   * @throws IOException
   */
  public List<UnsettledBet> evaluate(Reader settledReader, Reader unsettledReader) throws IOException {
    Map<Long, Customer> customers = new HashMap<Long, Customer>();
    List<SettledBet> settledBets = settledBetParser.parse(settledReader, true);
    for (SettledBet settledBet : settledBets) {
      getCustomer(customers, settledBet.getCustomerId()).addSettledBet(settledBet);
    }
    DecimalFormat decimalFormat = new DecimalFormat("#.##");
    List<UnsettledBet> unsettledBets = unsettledBetParser.parse(unsettledReader, true);
    for (UnsettledBet unsettledBet : unsettledBets) {
      Customer customer = getCustomer(customers, unsettledBet.getCustomerId());
      double successRate = customer.getSuccessRate();
      if (successRate > 0.6) {
        unsettledBet.addRisk(RiskType.SUCCESS_RATE,
                "Success rate: " + decimalFormat.format(successRate * 100) + "%");
      }
      double averageStake = customer.getAverageStake();
      double stakeRatio = unsettledBet.getStake() / averageStake;
      if (stakeRatio > 10) {
        RiskType type = RiskType.STAKE_AVERAGE;
        if (stakeRatio > 30) {
          type = RiskType.STAKE_AVERAGE_HIGH;
        }
        unsettledBet.addRisk(type,
                "Stake is " + decimalFormat.format(stakeRatio) + " times higher than average");
      }
      double toWin = unsettledBet.getToWin();
      if (toWin > 1000.0) {
        unsettledBet.addRisk(RiskType.STAKE_AMOUNT,
                "Stake: $" + decimalFormat.format(toWin));
      }
    }
    return unsettledBets;
  }
  private static Customer getCustomer(Map<Long, Customer> customers, long id) {
    Customer customer = customers.get(id);
    if (customer == null) {
      customer = new Customer(id);
      customers.put(id, customer);
    }
    return customer;
  }
}