#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# BioSTEAM: The Biorefinery Simulation and Techno-Economic Analysis Modules
# Copyright (C) 2020-2021, Yoel Cortes-Pena <yoelcortes@gmail.com>
# Bioindustrial-Park: BioSTEAM's Premier Biorefinery Models and Results
# Copyright (C) 2021, Yalin Li <yalinli2@illinois.edu>
#
# Part of this module is based on the lipidcane biorefinery:
# https://github.com/BioSTEAMDevelopmentGroup/Bioindustrial-Park/tree/master/BioSTEAM%202.x.x/biorefineries/lipidcane
#
# This module is under the UIUC open-source license. See
# github.com/BioSTEAMDevelopmentGroup/biosteam/blob/master/LICENSE.txt
# for license details.

import biosteam  as bst
from biosteam import main_flowsheet as F
from biorefineries import (
    lipidcane as lc,
    sugarcane as sc
    )

# from biorefineries.wwt import (
#     create_lc_chemicals,
#     lc_price, new_price, load_cs_settings,
#     create_wastewater_treatment_system
#     )
# from biorefineries.utils import get_MESP
from _chemicals import create_lc_chemicals
from _settings import lc_price, new_price, load_lc_settings
from _wwt_sys import create_wastewater_treatment_system
from utils import get_MESP


# %%

# =============================================================================
# Function to make the system
# =============================================================================

load_lc_settings()
chems = create_lc_chemicals()
bst.settings.set_thermo(chems)

@bst.SystemFactory(
    ID='lipidcane_sys',
    ins=[*lc.create_juicing_and_lipid_extraction_system.ins,
         sc.create_sucrose_to_ethanol_system.ins[1]],
    outs=[dict(ID='ethanol', price=lc_price['Ethanol']),
          dict(ID='biodiesel', price=lc_price['Biodiesel']),
          dict(ID='crude_glycerol', price=lc_price['Crude glycerol']),
          dict(ID='emissions'),
          dict(ID='ash_disposal')]
)
def create_lc_system(ins, outs, **wwt_kwargs):
    s = F.stream
    u = F.unit

    lipidcane, enzyme, H3PO4, lime, polymer, denaturant = ins
    ethanol, biodiesel, crude_glycerol, emissions, ash_disposal = outs

    feedstock_handling_sys = lc.create_feedstock_handling_system(
        ins=lipidcane,
        mockup=True,
    )

    ### Oil and juice separation ###
    juicing_and_lipid_extraction_sys = lc.create_juicing_and_lipid_extraction_system(
        ins=[feedstock_handling_sys-0, enzyme, H3PO4, lime, polymer],
        mockup=True,
    )

    ### Ethanol section ###
    ethanol_production_sys = sc.create_sucrose_to_ethanol_system(
        ins=[juicing_and_lipid_extraction_sys-0, denaturant],
        outs=[ethanol, 'vinasse'],
        mockup=True,
    )

    ### Biodiesel section ###
    # Fresh degummed oil
    oil = juicing_and_lipid_extraction_sys-1
    lc.create_transesterification_and_biodiesel_separation_system(
        ins=oil,
        outs=[biodiesel, crude_glycerol],
        mockup=True,
    )

    ### Wastewater treatment ###
    M305 = bst.Mixer(
        'M305',
        ins=(juicing_and_lipid_extraction_sys-4,
             juicing_and_lipid_extraction_sys-3,
             *ethanol_production_sys-[2, 3]),
        outs='wastewater',
    )

    create_wastewater_treatment_system(
        ins=[ethanol_production_sys-1, M305-0],
        outs=['biogas', 'sludge_S603', 'recycled_water', 'brine'],
        mockup=True,
        R601_kwargs={'method': 'lumped'},
        **wwt_kwargs,
    )

    ### Facilities ###
    bst.units.BoilerTurbogenerator('BT',
                                   (juicing_and_lipid_extraction_sys-2, u.M602-0,
                                    'boiler_makeup_water', 'natural_gas', '', ''),
                                   (emissions, 'rejected_water_and_blowdown', ash_disposal),
                                   boiler_efficiency=0.80,
                                   turbogenerator_efficiency=0.85)
    bst.units.CoolingTower('CT')
    bst.units.ChilledWaterPackage('CWP')

    makeup_water_streams = (s.cooling_tower_makeup_water,
                            s.boiler_makeup_water)
    process_water_streams = (s.imbibition_water,
                             s.biodiesel_wash_water,
                             s.oil_wash_water,
                             s.rvf_wash_water,
                             s.stripping_water,
                             s.lipid_wash_water,
                             s.dilution_water,
                             *makeup_water_streams)
    makeup_water = bst.Stream('makeup_water', price=0.000254)
    bst.units.ProcessWaterCenter('PWC',
                                 (u.S604-0, # recycled wastewater from reverse osmosis
                                 makeup_water),
                                 (),
                                 None,
                                 makeup_water_streams,
                                 process_water_streams)

    plant_air = bst.Stream('plant_air', N2=83333, units='kg/hr')
    ADP = bst.facilities.AirDistributionPackage('ADP', plant_air)
    @ADP.add_specification(run=True)
    def adjust_plant_air():
        plant_air.imass['N2'] = 0.8 * feedstock_handling_sys.ins[0].F_mass

    F301 = u.F301
    D303 = u.D303
    bst.HeatExchangerNetwork('HXN', units=[F301, D303])


# %%

# =============================================================================
# Create the system
# =============================================================================

flowsheet = bst.Flowsheet('wwt_lipidcane')
F.set_flowsheet(flowsheet)
lipidcane_sys = create_lc_system(skip_R601=True, skip_R602=True)
u = F.unit

lipidcane_sys.simulate()
lipidcane_tea = lc.create_tea(lipidcane_sys)
ethanol = F.stream.ethanol

# Compare MESP
original_IRR = 0.2108
lipidcane_tea.IRR = lc.lipidcane_tea.IRR = original_IRR
print(f'\n\nIRR = {original_IRR:.0%}')
lc.wastewater.price = 0.
MESP_old = get_MESP(lc.ethanol, lc.lipidcane_tea, 'old lc sys w/o ww cost')
lc.wastewater.price = new_price['Wastewater']
MESP_old = get_MESP(lc.ethanol, lc.lipidcane_tea, 'old lc sys w ww cost')
MESP_new = get_MESP(ethanol, lipidcane_tea, 'new lc sys')

lipidcane_tea.IRR = lc.lipidcane_tea.IRR = 0.1
ethanol.price = lc.ethanol.price = lc_price['Ethanol']
assert(lipidcane_tea.IRR==lc.lipidcane_tea.IRR)
print(f'\n\nIRR = {lipidcane_tea.IRR:.0%}')
lc.wastewater.price = 0.
MESP_old = get_MESP(lc.ethanol, lc.lipidcane_tea, 'old lc sys w/o ww cost')
lc.wastewater.price = new_price['Wastewater']
MESP_old = get_MESP(lc.ethanol, lc.lipidcane_tea, 'old lc sys w ww cost')
MESP_new = get_MESP(ethanol, lipidcane_tea, 'new lc sys')


# %%

# =============================================================================
# Sum up results
# =============================================================================

wwt_units = [i for i in u if i.ID[1:3]=='60']
new_capexes = {i.ID: i.installed_cost/1e6 for i in wwt_units}
new_capex = sum(i for i in new_capexes.values())

new_powers_wwt = {i.ID: i.power_utility.rate/1e3 for i in wwt_units}
new_power_wwt = sum(i for i in new_powers_wwt.values())
new_power_tot = sum(i.power_utility.consumption for i in lipidcane_sys.units)/1e3
new_power_ratio = new_power_wwt / new_power_tot

new_power_net = sum(i.power_utility.rate for i in lipidcane_sys.units)/1e3

s = F.stream
# Hf in kJ/hr
net_e = (s.biodiesel.Hf+s.ethanol.Hf)/3600/1e3 + u.BT.power_utility.rate/1e3
net_e_ratio = net_e/(s.lipidcane.Hf/3600/1e3)

# # A lot (twice as ethanol) goes to filter_cake
# s.filter_cake.Hf/3600/1e3

# For energy-based allocation between ethanol and biodiesel
ratio = s.ethanol.Hf/(s.ethanol.Hf+s.biodiesel.Hf)
# Water
water_usage = u.PWC.F_mass_in*ratio/s.ethanol.F_mass # 19 kg/kg
water_consumption = (u.PWC.ins[1].F_mass-u.PWC.outs[1].F_mass) * \
    ratio/s.ethanol.F_mass # about -8.8 kg/kg since lipidcane has 70% of water

# Wastewater
from utils import compute_stream_COD
wastewater = u.M601.F_mass_in/s.ethanol.F_mass # about 26 kg/kg
COD = compute_stream_COD(u.M601.outs[0]) # only about 3.6 g COD/L

# Ratios for IC design
# from _utils import get_CN_ratio
# R601_CN = get_CN_ratio(u.R601._inf)