def fetchSection1_11_windPLF(appDbConnStr: str, startDt: dt.datetime,
                             endDt: dt.datetime) -> ISection_1_11_PLFCUF:
    constituentsInfos = getREConstituentsMappings()
    mRepo = MetricsDataRepo(appDbConnStr)

    numOfDays = (endDt - startDt).days + 1

    soFarHighestAllEntityGenVals = mRepo.getSoFarHighestAllEntityData(
        'soFarHighestWindGen', addMonths(startDt, -1))
    soFarHighestGenLookUp = {}
    for v in soFarHighestAllEntityGenVals:
        soFarHighestGenLookUp[v['constituent']] = {
            'value': v['data_value'],
            'ts': v['data_time']
        }

    dispRows: List[IPLFCUFDataRow] = []
    for cIter in range(len(constituentsInfos)):
        constInfo = constituentsInfos[cIter]

        if (math.isnan(constInfo['windCapacity'])):
            continue

        maxGenData = mRepo.getEntityMetricHourlyData(constInfo["entity_tag"],
                                                     "Wind(MW)", startDt,
                                                     endDt)

        if constInfo['entity_tag'] == 'central':
            windEnerConsumption = mRepo.getEntityMetricDailyData(
                'wr', 'CGS Wind(Mus)', startDt, endDt)
        elif constInfo['entity_tag'] == 'wr':
            windEnerConsumption = mRepo.getEntityMetricDailyData(
                'wr', "Wind(MU)", startDt, endDt)
            cgsWindEnerConsumption = mRepo.getEntityMetricDailyData(
                'wr', 'CGS Wind(Mus)', startDt, endDt)
            for w, c in zip(windEnerConsumption, cgsWindEnerConsumption):
                w["data_value"] += c["data_value"]
        else:
            windEnerConsumption = mRepo.getEntityMetricDailyData(
                constInfo['entity_tag'], 'Wind(MU)', startDt, endDt)

        energyConsumption = mRepo.getEntityMetricDailyData(
            constInfo['entity_tag'], 'Consumption(MU)', startDt, endDt)

        maxGenDf = pd.DataFrame(maxGenData)
        maxGenDf = maxGenDf.pivot(index='time_stamp',
                                  columns='metric_name',
                                  values='data_value')
        windEnerConsumptionSum = pd.DataFrame(windEnerConsumption).groupby(
            'entity_tag').sum().iloc[0]['data_value']

        if (len(energyConsumption) == 0):
            # This is for central sector as we dont have consumption data
            # calculate mu from mw
            # df = pd.DataFrame(maxGenData)
            # average = df.groupby('entity_tag').mean()
            # windEnerConsumptionSumDf = average * 0.024 * numOfDays #To Calculate Avg MU from MW
            # windEnerConsumptionSum = windEnerConsumptionSumDf.iloc[0]['data_value']
            EnerConsumptionSum = 0
            penetrationLevel = 0
        else:
            EnerConsumptionSum = pd.DataFrame(energyConsumption).groupby(
                'entity_tag').sum().iloc[0]['data_value']
            penetrationLevel = round(
                (windEnerConsumptionSum / EnerConsumptionSum) * 100, 2)

        maxWind = maxGenDf["Wind(MW)"].max()
        maxWindDt = maxGenDf["Wind(MW)"].idxmax()

        plf = (windEnerConsumptionSum *
               1000) / (int(constInfo['windCapacity']) * 24 * numOfDays)
        cuf = maxWind * 100 / (int(constInfo['windCapacity']))

        prevHighestWindObj = soFarHighestGenLookUp[constInfo["entity_tag"]]
        newHighestWind = maxWind
        newHighestWindTime = maxWindDt.to_pydatetime()

        if newHighestWind < prevHighestWindObj["value"]:
            newHighestWind = prevHighestWindObj["value"]
            newHighestWindTime = prevHighestWindObj["ts"]

        mRepo.insertSoFarHighest(constInfo['entity_tag'],
                                 "soFarHighestWindGen", startDt,
                                 newHighestWind, newHighestWindTime)
        # soFarHighestAllEntityGenVals = mRepo.getSoFarHighestAllEntityData(
        # 'soFarHighestWindGen', startDt)
        # soFarHighestGenLookUp = {}
        # for v in soFarHighestAllEntityGenVals:
        #     soFarHighestGenLookUp[v['constituent']] = {
        #     'value': v['data_value'], 'ts': v['data_time']}
        so_far_high_gen_str = str(
            round(newHighestWind)) + ' on ' + dt.datetime.strftime(
                newHighestWindTime,
                '%d-%b-%Y') + ' at ' + dt.datetime.strftime(
                    newHighestWindTime, '%H:%S')

        const_display_row: IPLFCUFDataRow = {
            'entity': constInfo['display_name'],
            'capacityMW': round(constInfo['windCapacity']),
            'maxgenerationMW': round(maxWind),
            'soFarHighestGenMW': so_far_high_gen_str,
            'energyGeneration': round(windEnerConsumptionSum),
            'energyConsumption': round(EnerConsumptionSum),
            'penetration': penetrationLevel,
            'plf': round(plf * 100),
            'cuf': round(cuf)
        }
        dispRows.append(const_display_row)

    secData: ISection_1_11_PLFCUF = {"so_far_hig_win_gen_plf": dispRows}
    return secData
def fetchSection1_3_bContext(appDbConnStr: str, startDt: dt.datetime,
                             endDt: dt.datetime) -> ISection_1_3_b:
    constituentsInfos = getConstituentsMappings()
    mRepo = MetricsDataRepo(appDbConnStr)

    soFarHighestAllEntityReqVals = mRepo.getSoFarHighestAllEntityData(
        'soFarHighestRequirement', addMonths(startDt, -1))
    soFarHighestReqLookUp = {}
    for v in soFarHighestAllEntityReqVals:
        soFarHighestReqLookUp[v['constituent']] = {
            'value': v['data_value'],
            'ts': v['data_time']
        }

    soFarHighestAllEntityAvailVals = mRepo.getSoFarHighestAllEntityData(
        'soFarHighestAvailability', addMonths(startDt, -1))
    soFarHighestAvailLookUp = {}
    for v in soFarHighestAllEntityAvailVals:
        soFarHighestAvailLookUp[v['constituent']] = {
            'value': v['data_value'],
            'ts': v['data_time']
        }
    dispRows: List[ISoFarHighestDataRow] = []
    for cIter in range(len(constituentsInfos)):
        constInfo = constituentsInfos[cIter]
        availData = mRepo.getEntityMetricHourlyData(constInfo["entity_tag"],
                                                    "Demand(MW)", startDt,
                                                    endDt)
        loadSheddingData = mRepo.getEntityMetricHourlyData(
            constInfo["entity_tag"], "Load Shedding(MW)", startDt, endDt)
        availReqData = availData + loadSheddingData
        availReqDataDf = pd.DataFrame(availReqData)
        availReqDataDf = availReqDataDf.pivot(index='time_stamp',
                                              columns='metric_name',
                                              values='data_value')
        availReqDataDf.reset_index(inplace=True)
        availReqDataDf["Requirement"] = availReqDataDf["Demand(MW)"] + \
            availReqDataDf["Load Shedding(MW)"]
        maxReq = availReqDataDf["Requirement"].max()
        maxReqDt = availReqDataDf["time_stamp"].loc[
            availReqDataDf["Requirement"].idxmax()]
        maxAvail = availReqDataDf["Demand(MW)"].max()
        maxAvailDt = availReqDataDf["time_stamp"].loc[
            availReqDataDf["Demand(MW)"].idxmax()]
        maxShortagePerc = round(100 * (maxReq - maxAvail) / maxAvail, 2)

        prevHighestReqObj = soFarHighestReqLookUp[constInfo["entity_tag"]]
        newHighestReq = maxReq
        newHighestReqTime = maxReqDt.to_pydatetime()
        if newHighestReq < prevHighestReqObj["value"]:
            newHighestReq = prevHighestReqObj["value"]
            newHighestReqTime = prevHighestReqObj["ts"]

        prevHighestAvailObj = soFarHighestAvailLookUp[constInfo["entity_tag"]]
        newHighestAvail = maxAvail
        newHighestAvailTime = maxAvailDt.to_pydatetime()
        if newHighestAvail < prevHighestAvailObj["value"]:
            newHighestAvail = prevHighestAvailObj["value"]
            newHighestAvailTime = prevHighestAvailObj["ts"]
        newHighestShortagePerc = round(
            100 * (newHighestReq - newHighestAvail) / newHighestAvail, 2)
        newHighestAvailTime = newHighestAvailTime
        newHighestReqTime = newHighestReqTime
        mRepo.insertSoFarHighest(constInfo['entity_tag'],
                                 "soFarHighestAvailability", startDt,
                                 newHighestAvail, newHighestAvailTime)
        mRepo.insertSoFarHighest(constInfo['entity_tag'],
                                 "soFarHighestRequirement", startDt,
                                 newHighestReq, newHighestReqTime)

        const_display_row: ISoFarHighestDataRow = {
            'entity':
            constInfo['display_name'],
            'peakReqMW':
            round(maxReq),
            'peakAvailMW':
            round(maxAvail),
            'shortage_X':
            maxShortagePerc,
            'highestReqMW':
            round(newHighestReq),
            'highestAvailMW':
            round(newHighestAvail),
            'shortage_Y':
            newHighestShortagePerc,
            'highestReqMWDateStr':
            'Max on {0} at {1} hrs'.format(
                dt.datetime.strftime(newHighestReqTime, "%d.%m.%y"),
                dt.datetime.strftime(newHighestReqTime, "%H:%M")),
            'highestAvailMWDateStr':
            'Max on {0} at {1} hrs'.format(
                dt.datetime.strftime(newHighestAvailTime, "%d.%m.%y"),
                dt.datetime.strftime(newHighestAvailTime, "%H:%M"))
        }
        dispRows.append(const_display_row)

    secData: ISection_1_3_b = {"so_far_hig_req_avail": dispRows}
    return secData