package info.nightscout.androidaps.db;

import com.j256.ormlite.field.DatabaseField;
import com.j256.ormlite.table.DatabaseTable;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Calendar;
import java.util.Date;
import java.util.TimeZone;

import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.data.Iob;
import info.nightscout.client.data.NSProfile;

@DatabaseTable(tableName = "TempBasals")
public class TempBasal {
    private static Logger log = LoggerFactory.getLogger(TempBasal.class);

    public long getTimeIndex() {
        return (long) Math.ceil(timeStart.getTime() / 60000d);
    }

    public void setTimeIndex(long timeIndex) {
        this.timeIndex = timeIndex;
    }

    @DatabaseField(id = true, useGetSet = true)
    public long timeIndex;


    @DatabaseField
    public Date timeStart;

    @DatabaseField
    public Date timeEnd;

    @DatabaseField
    public int percent;     // In % of current basal.  100% == current basal

    @DatabaseField
    public Double absolute;    // Absolute value in U

    @DatabaseField
    public int duration;    // in minutes

    @DatabaseField
    public boolean isExtended; // true if set as extended bolus

    @DatabaseField
    public boolean isAbsolute; // true if if set as absolute value in U


    public Iob iobCalc(Date time) {
        Iob result = new Iob();
        NSProfile profile = MainApp.getNSProfile();

        if (profile == null)
            return result;

        int realDuration = getRealDuration();

        if (realDuration > 0) {
            Double netBasalRate = 0d;
            Double basalRate = profile.getBasal(profile.secondsFromMidnight(time));
            Double tempBolusSize = 0.05;

            if (this.isAbsolute) {
                netBasalRate = this.absolute - basalRate;
            } else {
                netBasalRate = (this.percent - 100) / 100d * basalRate;
            }

            result.netRatio = netBasalRate;
            Double netBasalAmount = Math.round(netBasalRate * realDuration * 10 / 6) / 100d;
            result.netInsulin = netBasalAmount;
            if (netBasalAmount < 0.1) {
                tempBolusSize = 0.01;
            }
            if (netBasalRate < 0) {
                tempBolusSize = -tempBolusSize;
            }
            Long tempBolusCount = Math.round(netBasalAmount / tempBolusSize);
            if (tempBolusCount > 0) {
                Long tempBolusSpacing = realDuration / tempBolusCount;
                for (Long j = 0l; j < tempBolusCount; j++) {
                    Treatment tempBolusPart = new Treatment();
                    tempBolusPart.insulin = tempBolusSize;
                    Long date = this.timeStart.getTime() + j * tempBolusSpacing * 60 * 1000;
                    tempBolusPart.created_at = new Date(date);
                    Iob iob = tempBolusPart.iobCalc(time);
                    result.plus(iob);
                }
            }
        }
        return result;
    }

    /*
        public Iob calcIob() {
            Iob iob = new Iob();

            long msAgo = getMillisecondsFromStart();
            Calendar startAdjusted = Calendar.getInstance(TimeZone.getTimeZone("UTC"));
            startAdjusted.setTime(this.timeStart);
            int minutes = startAdjusted.get(Calendar.MINUTE);
            minutes = minutes % 4;
            if (startAdjusted.get(Calendar.SECOND) > 0 && minutes == 0) {
                minutes += 4;
            }
            startAdjusted.add(Calendar.MINUTE, minutes);
            startAdjusted.set(Calendar.SECOND, 0);

            IobCalc iobCalc = new IobCalc();
            iobCalc.setTime(new Date());
            iobCalc.setAmount(-1.0d * (baseRatio - tempRatio) / 15.0d / 100.0d);

            long timeStartTime = startAdjusted.getTimeInMillis();
            Date currentTimeEnd = timeEnd;
            if (currentTimeEnd == null) {
                currentTimeEnd = new Date();
                if (getPlannedTimeEnd().getTime() < currentTimeEnd.getTime()) {
                    currentTimeEnd = getPlannedTimeEnd();
                }
            }
            for (long time = timeStartTime; time < currentTimeEnd.getTime(); time += 4 * 60_000) {
                Date start = new Date(time);

                iobCalc.setTimeStart(start);
                iob.plus(iobCalc.invoke());
            }

            if (Settings.logTempIOBCalculation) {
                log.debug("TempIOB start: " + this.timeStart + " end: " + this.timeEnd + " Percent: " + this.percent + " Duration: " + this.duration + " CalcDurat: " + (int) ((currentTimeEnd.getTime() - this.timeStart.getTime()) / 1000 / 60)
                        + "min minAgo: " + (int) (msAgo / 1000 / 60) + " IOB: " + iob.iobContrib + " Activity: " + iob.activityContrib + " Impact: " + (-0.01d * (baseRatio - tempRatio) * ((currentTimeEnd.getTime() - this.timeStart.getTime()) / 1000 / 60) / 60)
                );
            }

            return iob;
        }
    */
    // Determine end of basal
    public Date getTimeEnd() {
        Date tempBasalTimePlannedEnd = getPlannedTimeEnd();
        Date now = new Date();

        if (timeEnd != null && timeEnd.getTime() < tempBasalTimePlannedEnd.getTime()) {
            tempBasalTimePlannedEnd = timeEnd;
        }

        if (now.getTime() < tempBasalTimePlannedEnd.getTime())
            tempBasalTimePlannedEnd = now;

        return tempBasalTimePlannedEnd;
    }

    public Date getPlannedTimeEnd() {
        return new Date(timeStart.getTime() + 60 * 1_000 * duration);
    }

    public int getRealDuration() {
        Long msecs = getTimeEnd().getTime() - timeStart.getTime();
        return (int) (msecs / 60 / 1000);
    }

    public long getMillisecondsFromStart() {
        return new Date().getTime() - timeStart.getTime();
    }

    public int getRemainingMinutes() {
        long remainingMin = (getTimeEnd().getTime() - new Date().getTime()) / 1000 / 60;
        return (remainingMin < 0) ? 0 : (int) remainingMin;
    }

    @Override
    public String toString() {
        return "TempBasal{" +
                "timeIndex=" + timeIndex +
                ", timeStart=" + timeStart +
                ", timeEnd=" + timeEnd +
                ", percent=" + percent +
                ", absolute=" + absolute +
                ", duration=" + duration +
                ", isAbsolute=" + isAbsolute +
                ", isExtended=" + isExtended +
                '}';
    }
}