
import {Log} from "fme-logger";
var L = new Log("FreeBarchart");
import * as _m from "moment-timezone";
import * as request from "request-promise-native";
import {FmeQuote} from "fme-quotes-models";

interface EsQuote {

}
interface History {

}



function convert (x:any,type:string,interval:number) {
    var obj = new FmeQuote();
    obj.symbol = x.symbol.toUpperCase();

    obj.YYYYMMDD = _m(x.timestamp).format("YYYYMMDD");
    obj.timeHHMM = _m(x.timestamp).format("HHmm");
    obj.time = _m(x.timestamp).hours()*60+_m(x.timestamp).minutes();
    obj.timestamp = x.timestamp;
    
    obj.open = x.open;
    obj.close = x.close;
    obj.high = x.high;
    obj.low = x.low;
    obj.avg = (x.open+x.close+x.high+x.low)/4;

    obj.volume = x.volume;
    obj.source = "barchart-free";
    obj.decimalPoints = 2;

    obj.interval = interval;
    obj.type = type;
    return obj
}

export class FreeBarchart {
    version = "1.0.0";
    host = "marketdata.websol.barchart.com";
    endpoint = "getHistory.json";
 //   symbol = "ES*1";
    symbol = "SPY";
    type = "minutes";
    types = ["ticks", "minutes", "nearbyMinutes", "formTMinutes", "daily", "dailyNearest", "dailyContinue", "weekly", "weeklyNearest",
    "weeklyContinue", "monthly", "monthlyNearest", "monthlyContinue", "quarterly", "quarterlyNearest", "quarterlyContinue", "yearly",
    "yearlyNearest", "yearlyContinue"];
    typesSingleDay = ["ticks","minutes","nearbyMinutes","formTMinutes"];
    interval = 1;
    startTime = 9*60 + 30;  // default startTime == 9:30;
    endTime = 16*60 + 0;    // default endTime = 4pm;
    targetDate = new Date();

    //
    // @KEY = FREE BARCHART KEY STRING
    // @SYMBOL = BARCHART SYMBOL
    // @FRAME = TIMEFRAME = "minute","day","week"
    // @Interval = number (1,2,3) (combines with FRAME to complete the reqeust);
    //

    constructor(private key:string,symbol:string,frame:string,interval:number,targetDate:Date,startTime?:number,endTime?:number) {
        this.symbol = symbol;
    //
    // => convert futures contract to dated contract based on target date
    //    
        if (this.symbol.toLowerCase().indexOf("_f")> -1) {
            var contract = new ContractConversion()
            var expiry = 3;
            if (symbol.toLowerCase().indexOf("cl")> -1) expiry = 1;
            this.symbol = this.symbol.toLowerCase().replace("_f",contract.findCode(targetDate,expiry))
        }
           
        this.type = frame.toLowerCase().trim();
        if (startTime) this.startTime == startTime;
        if (endTime) this.endTime == endTime;
        this.targetDate = targetDate;

        if (this.types.indexOf(this.type) == -1 ) {
            L.error("Invalid type passed",this.types,"valid types are",JSON.stringify(this.types))
            return;
        }

        if (!interval) this.interval = 1; else this.interval = interval;;
    }

    

    getDailyMinutes = async () => {
        var type = this.type.trim().toLowerCase();
        var symbol = this.symbol.trim().toLowerCase();
        var startDate = _m(this.targetDate).format("YYYYMMDD");
        
        var req = "/"+this.endpoint+"?key="+this.key+"&symbol="+this.symbol+"&type="+type+"&startDate="+startDate+"&interval="+this.interval;
        var fullUrl = "http://"+this.host+req;
        L.info("requesting:",fullUrl);
       
        try {
            var results = await request(fullUrl)
            var rtn = JSON.parse(results).results; 
			if (!rtn) {
				L.info("barchart did not return a value for date",startDate)
				return null;
			}
		}catch(err) {
            L.error(err,results);
            return
        }
        L.info("Rtn is",rtn.length,rtn[rtn.length-1]);
        var filter:FmeQuote[] = [];
        if (this.typesSingleDay.indexOf(type) > -1) {
            filter = rtn.filter((x:any) =>{return _m(x.timestamp).format("YYYYMMDD") == startDate } ).map((a:any)=>{ return convert(a,type,this.interval)} ) as FmeQuote[];
        } else {
            filter = rtn.filter.map((a:any)=>{ return convert(a,type,this.interval)} ) as FmeQuote[];
        }
        
       // L.info("filter length is",filter.length,filter[0],filter[filter.length-1]);
      //  return filter.filter((a) => {return  a.time >= this.startTime && a.time <= this.endTime});
        return filter.map( (a:any) => {return convert(a,type,this.interval)} )
    }


}

export class Conversion {
	inputSymbol:string = "SPY";
	symbol: string = "spy";
	exchange: string = "nyse";
	timeAdjust?:number = 0;
	expiryLength? = 3
}

export class ContractConversion {
	codes = ["F","G","H","J","K","M","N","Q","U","V","X","Z"];
	rollOffset = 8 ; // number of days offset from expiration the roll is. 

//
// => find codes
//		Date: date to find code for
//		Length: Number of Months between contract roll, only supports monthly (1) or quarterly(3);
//	
	findCode =  (date:Date,length:number) => {
		
		
		if (length == 1) {
			if (_m(date).date() > 20) offset = 2;
			else offset = 2;
			var month = _m(date).month()+offset;
			return this.codes[month]+_m(date).format("YY");
		} 
		if(length == 3) {
			var quarter = _m(date).quarter();;  // quarter to find contract
			L.info("We are in this quarter",quarter);
		//
		// add either 2 or 5 to this number to get the contract
		// add 2 if the current date is before the expiration + rolloffset, else add 3. 
		//	
				
			var startOfMonth = _m(date).startOf("quarter").add(2,"months").clone();
			var today = startOfMonth.day();
			if (today == 6) var inc = 3
			else inc = 2;
			var expiration = startOfMonth.day(5).add(inc,"weeks");
			var rollover = expiration.clone().subtract(this.rollOffset,"days");
			L.info("Date",_m(date).format("YYYYMMDD"),"rollover",rollover.format("YYYYMMDD"));
			if ( date >= rollover.toDate()) var offset = quarter*3+2;
			else offset=quarter*3-1;
		//
		// => take care of annual roll at the end of the year!
		//
			var annualOffset = 0;
			if (offset > 11) {
				offset = offset - 12;
				annualOffset = 1;
			}
			L.info("expiration is",expiration.format("YYYYMMDD"),"roll over is",rollover.format("YYYYMMDD"),"offset is",offset)

			return this.codes[offset]+_m(date).add(annualOffset,"years").format("YY");
		}	
	}

}
       