/**
 * Copyright (C) 2016 - present by OpenGamma Inc. and the OpenGamma group of companies
 * <p>
 * Please see distribution for license.
 */
package net.corda.vega;

import com.google.common.collect.ImmutableList;
import com.opengamma.strata.basics.ReferenceData;
import com.opengamma.strata.basics.currency.Currency;
import com.opengamma.strata.basics.currency.FxRate;
import com.opengamma.strata.basics.currency.MultiCurrencyAmount;
import com.opengamma.strata.basics.date.Tenor;
import com.opengamma.strata.collect.io.ResourceLocator;
import com.opengamma.strata.collect.tuple.Triple;
import com.opengamma.strata.data.FxRateId;
import com.opengamma.strata.data.ImmutableMarketData;
import com.opengamma.strata.data.MarketData;
import com.opengamma.strata.data.MarketDataFxRateProvider;
import com.opengamma.strata.loader.csv.FxRatesCsvLoader;
import com.opengamma.strata.loader.csv.QuotesCsvLoader;
import com.opengamma.strata.loader.csv.RatesCalibrationCsvLoader;
import com.opengamma.strata.market.curve.CurveGroupDefinition;
import com.opengamma.strata.market.curve.CurveGroupName;
import com.opengamma.strata.market.observable.QuoteId;
import com.opengamma.strata.market.param.CurrencyParameterSensitivities;
import com.opengamma.strata.market.sensitivity.PointSensitivities;
import com.opengamma.strata.pricer.curve.CalibrationMeasures;
import com.opengamma.strata.pricer.curve.CurveCalibrator;
import com.opengamma.strata.pricer.rate.ImmutableRatesProvider;
import com.opengamma.strata.pricer.swap.DiscountingSwapProductPricer;
import com.opengamma.strata.product.common.BuySell;
import com.opengamma.strata.product.swap.ResolvedSwap;
import com.opengamma.strata.product.swap.ResolvedSwapTrade;
import com.opengamma.strata.product.swap.SwapTrade;
import com.opengamma.strata.product.swap.type.FixedIborSwapConventions;

import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDate;
import java.util.List;
import java.util.Map;

import static java.util.stream.Collectors.toList;

/**
 * A example of calculating the margin for a portfolio of two swaps using Strata and SIMM.
 */
public class SwapExampleX {

  public static final LocalDate VALUATION_DATE = LocalDate.of(2016, 6, 6);

  public static void main(String[] args) {
    CurveGroupDefinition curveGroupDefinition = loadCurveGroup();
    MarketData marketData = loadMarketData();
    List<SwapTrade> trades = ImmutableList.of(createVanillaFixedVsLibor3mSwap(), createVanillaFixedVsLibor6mSwap());
    CurveCalibrator calibrator = CurveCalibrator.of(1e-9, 1e-9, 100, CalibrationMeasures.PAR_SPREAD);
    ImmutableRatesProvider ratesProvider = calibrator.calibrate(curveGroupDefinition, marketData, ReferenceData.standard());
    MarketDataFxRateProvider fxRateProvider = MarketDataFxRateProvider.of(marketData);
    ImmutableRatesProvider combinedRatesProvider = ImmutableRatesProvider.combined(fxRateProvider, ratesProvider);

    List<ResolvedSwapTrade> resolvedTrades = trades.stream().map(trade -> trade.resolve(ReferenceData.standard())).collect(toList());
    DiscountingSwapProductPricer pricer = DiscountingSwapProductPricer.DEFAULT;

    CurrencyParameterSensitivities totalSensitivities = CurrencyParameterSensitivities.empty();
    MultiCurrencyAmount totalCurrencyExposure = MultiCurrencyAmount.empty();

    for (ResolvedSwapTrade resolvedTrade : resolvedTrades) {
      ResolvedSwap swap = resolvedTrade.getProduct();

      PointSensitivities pointSensitivities = pricer.presentValueSensitivity(swap, combinedRatesProvider).build();
      CurrencyParameterSensitivities sensitivities = combinedRatesProvider.parameterSensitivity(pointSensitivities);
      MultiCurrencyAmount currencyExposure = pricer.currencyExposure(swap, combinedRatesProvider);

      totalSensitivities = totalSensitivities.combinedWith(sensitivities);
      totalCurrencyExposure = totalCurrencyExposure.plus(currencyExposure);
    }
    //PortfolioNormalizer normalizer = new PortfolioNormalizer(Currency.EUR, combinedRatesProvider);
    //RwamBimmNotProductClassesCalculator calculatorTotal = new RwamBimmNotProductClassesCalculator(
    //    fxRateProvider,
    //    Currency.EUR,
    //    IsdaConfiguration.INSTANCE);
//
    //Triple<Double, Double, Double> margin = BimmAnalysisUtils.computeMargin(
    //    combinedRatesProvider,
    //    normalizer,
    //    calculatorTotal,
    //    totalSensitivities,
    //    totalCurrencyExposure);
//
    //System.out.println(margin);
  }

  //--------------------------------------------------------------------------------------------------

  /**
   * Load the market quotes and FX rates from data files.
   */
  private static MarketData loadMarketData() {
    Path dataDir = Paths.get("src/test/resources/data");
    Path quotesFile = dataDir.resolve("BIMM-MARKET-QUOTES-20160606.csv");
    Path fxFile = dataDir.resolve("BIMM-FX-RATES-20160606.csv");

    Map<QuoteId, Double> quotes = QuotesCsvLoader.load(VALUATION_DATE, ImmutableList.of(ResourceLocator.ofPath(quotesFile)));
    Map<FxRateId, FxRate> fxRates = FxRatesCsvLoader.load(VALUATION_DATE, ResourceLocator.ofPath(fxFile));
    return ImmutableMarketData.builder(VALUATION_DATE).addValueMap(quotes).addValueMap(fxRates).build();
  }

  /**
   * Loads the curve group definition from data files.
   *
   * A curve group maps from curve name to index for forward curves and curve name to currency for discount curves.
   */
  private static CurveGroupDefinition loadCurveGroup() {
    Path settingsDir = Paths.get("src/test/resources/settings");
    Map<CurveGroupName, CurveGroupDefinition> curveGroups = RatesCalibrationCsvLoader.load(
        ResourceLocator.ofPath(settingsDir.resolve("BIMM-groups-EUR.csv")),
        ResourceLocator.ofPath(settingsDir.resolve("BIMM-settings-EUR.csv")),
        ResourceLocator.ofPath(settingsDir.resolve("BIMM-nodes-EUR.csv")));
    return curveGroups.get(CurveGroupName.of("BIMM"));
  }

  //--------------------------------------------------------------------------------------------------

  private static SwapTrade createVanillaFixedVsLibor3mSwap() {
    return FixedIborSwapConventions.EUR_FIXED_1Y_EURIBOR_3M.createTrade(
            VALUATION_DATE,
        Tenor.TENOR_4Y,
        BuySell.BUY,
        200_000_000,
        0.015,
        ReferenceData.standard());
  }

  private static SwapTrade createVanillaFixedVsLibor6mSwap() {
    return FixedIborSwapConventions.EUR_FIXED_1Y_EURIBOR_6M.createTrade(
            VALUATION_DATE,
        Tenor.TENOR_10Y,
        BuySell.SELL,
        100_000_000,
        0.013,
        ReferenceData.standard());
  }
}
