package jforex;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;

import com.dukascopy.api.Configurable;
import com.dukascopy.api.Filter;
import com.dukascopy.api.IAccount;
import com.dukascopy.api.IBar;
import com.dukascopy.api.IConsole;
import com.dukascopy.api.IContext;
import com.dukascopy.api.IHistory;
import com.dukascopy.api.IMessage;
import com.dukascopy.api.IStrategy;
import com.dukascopy.api.ITick;
import com.dukascopy.api.Instrument;
import com.dukascopy.api.JFException;
import com.dukascopy.api.OfferSide;
import com.dukascopy.api.Period;
import com.dukascopy.api.util.DateUtils;

@RequiresFullAccess
public class TickBarStrategy implements IStrategy {
    private IContext context;
    private IHistory history;
    private IConsole console;

    @Configurable("Ticks output file")
    public File tickFile;

    @Configurable("Bars output file")
    public File barFile;

    private BufferedWriter ticksWriter;
    private BufferedWriter barsWriter;
    
    private int ticksCounter = 0;


    @Override
    public void onStart(IContext context) throws JFException {
        this.context = context;
        this.history = context.getHistory();
        this.console = context.getConsole();

        try {
            ticksWriter = new BufferedWriter(new FileWriter(tickFile));
            barsWriter = new BufferedWriter(new FileWriter(barFile));
        } catch (IOException e) {
            console.getErr().println(e.getMessage());
            context.stop();
        }
    }

    @Override
    public void onTick(Instrument instrument, ITick tick) throws JFException {
        ticksCounter++;
        writeTick(tick);
    }

    @Override
    public void onBar(Instrument instrument, Period period, IBar askBar, IBar bidBar) throws JFException {
        if (period == Period.WEEKLY) {
            List<IBar> weeklyBars = history.getBars(instrument, Period.DAILY, OfferSide.ASK, Filter.NO_FILTER,
                    1, askBar.getTime(), 6);

            writeBars(weeklyBars);
        }
    }

    @Override
    public void onMessage(IMessage message) throws JFException {

    }

    @Override
    public void onAccount(IAccount account) throws JFException {

    }

    @Override
    public void onStop() throws JFException {
        console.getOut().println("Ticks amount: " + ticksCounter);
    }

    private void writeTick(ITick tick) {
        double time = tick.getTime();
        double ask = tick.getAsk();
        double bid = tick.getBid();
        double askVolume = tick.getAskVolume();
        double bidVolume = tick.getBidVolume();
        String timeAsString = DateUtils.format(time);

        StringBuilder msgBuilder = new StringBuilder()
                .append("Tick time: ")
                .append(timeAsString)
                .append(" Ask: ")
                .append(ask)
                .append(" Bid: ")
                .append(bid)
                .append(" Ask volume: ")
                .append(askVolume)
                .append(" Bid volume: ")
                .append(bidVolume)
                .append("\r\n");

        try {
            ticksWriter.write(msgBuilder.toString());
            ticksWriter.flush();
        } catch (IOException e) {
            console.getErr().println(e.getMessage());
        }
    }

    private void writeBars(List<IBar> weeklyBars) {
        weeklyBars.stream()
                .map(bar -> {
                    long barTime = bar.getTime();
                    double barOpen = bar.getOpen();
                    double barHigh = bar.getHigh();
                    double barLow = bar.getLow();
                    double barClose = bar.getClose();
                    String barTimeAsString = DateUtils.format(barTime);

                    StringBuilder barRowBuilder = new StringBuilder()
                            .append("Bar time: ")
                            .append(barTimeAsString)
                            .append(" Open: ")
                            .append(barOpen)
                            .append(" High: ")
                            .append(barHigh)
                            .append(" Low: ")
                            .append(barLow)
                            .append(" Close: ")
                            .append(barClose);

                    return barRowBuilder.toString();
                })
                .forEach(row -> {
                    try {
                        barsWriter.write(row + "\r\n");
                        barsWriter.flush();
                    } catch (IOException e) {
                        console.getErr().println(e.getMessage());
                    }
                });

        try {
            barsWriter.write("\r\n" + "\r\n");
        } catch (IOException e) {
            console.getErr().println(e.getMessage());
        }
    }
}

