 # -*- coding: utf-8 -*-
"""
Created on Wed Aug 23 07:56:23 2023

@author: lcassan
"""
import argparse
from os import getcwd, path
import sys
import os

#!/usr/bin/env python3
"""
Script principal de CEPHEE
Peut être exécuté directement ou appelé depuis mesh_cli.py
"""

import sys
import os

# -----------------------------
# Helper pour gérer imports robustes
# -----------------------------
'''
# Ajouter le dossier parent de cephee au sys.path
project_root = os.path.dirname(os.path.abspath(__file__))
if project_root not in sys.path:
    sys.path.insert(0, project_root)
'''
# -----------------------------
# Imports internes de core
# -----------------------------
from core import ModelCatchment

import geopandas as gpd
from core.ModelCatchment import ModelCatchment
from core.Reach import Reach
from tatooinemesher.coord import Coord
from core.Hydraulics import *
from core.CrossSection import *

from core.Data import *
from core.Bathymetrics import *
from core.postCEPHEE import *
from core.Parameters import read_param

hydro_lib = None
try:
    import pysheds
    computeGlobal_avail = True
    hydro_lib='pysheds'
except ImportError:
    computeGlobal_avail = False

try:
    import pyflwdir
    computeGlobal_avail = True
    hydro_lib = 'pyflwdir'
except ImportError:
    computeGlobal_avail = False


'''
Exemple de fichier CLI permettant une utilisation classique de CEPHEE.
Les choix des opérations à faire est faite dans la classe paramètre 
ainsi quel'ensemble des chemin d'accés et des valeurs numériques des paramètres

ce fichier permet de choisir si les cross section seront créés ou lues dans un fichier
par défaut les sections importées ne sont pas reprojetéées car elles sont utilisées pour creuser le lit mineur
On peut aussi choisir de creuser le MNT en fonctin du calcul fait

'''

def cephee_cli(params, model = None, post = False, bathy = False, nochannel = False, save =False):

    if computeGlobal_avail == False:
        params['C']['computeGlobal'] = None

    #--------DATA process-------
    BV1 = ModelCatchment(qgis_mode=False)
    run_data_process(BV1, params, hydro_lib, nochannel = nochannel)

    hydro_network_filepath = os.path.join(params.work_path, 'hydro_network.shp')
    BV1.hydro_network.to_file(hydro_network_filepath, driver="ESRI Shapefile")
    network_filepath = os.path.join(params.work_path, 'ordered_network.shp')
    BV1.ordered_network.to_file(network_filepath, driver="ESRI Shapefile")
    if BV1.outline:
        if type(BV1.outline) == list:
            gdf = gpd.GeoDataFrame(geometry=BV1.outline, crs=BV1.crs)
        else:
            gdf = gpd.GeoDataFrame(geometry=[BV1.outline], crs=BV1.crs)
        gdf.to_file(os.path.join(params.work_path, 'contours.shp'), driver="ESRI Shapefile")
    if not BV1.init_mode in [-1,11, 12]:
        BV1.junction.to_file(os.path.join(params.work_path, 'junction.shp'), driver="ESRI Shapefile")

    # --------CROSS SECTIONS process-------

    if not nochannel:
        BV_global =BV1
        BV_global.createReach()
        select_XS_option(BV_global, params)
    else:
        new_reach = []
        BV_global = ModelCatchment(qgis_mode=False)
        BV_global.ordered_network = BV1.ordered_network  # on fait un BV global pour appliquer remove_XS

        for i in range(len(BV1.ordered_network)):

            BV1.ordered_network = BV1.ordered_network.reset_index(drop=True)
            BV1.list_of_outlet = [[BV1.ordered_network.loc[i, 'River'], [BV1.ordered_network.loc[i, 'River']], 0]]
            BV1.createReach()
            BV1.interpolateReach(params['XS']['creation_step'])
            params['I']['XS_filepath'] = None
            select_XS_option(BV1, params)

            if not params['I']['riverbanks_filepath']:
                BV1.compute_slope(params['N']['npoly'])
                impose_water_depth(BV1, params)
                reduceXStobank(BV1, params['XS']['distSearchMin'], 'channel')

            if len(BV1.reach[0].section_list) > 3:
                new_reach.append(BV1.reach[0])
                new_reach[-1].geodata['Reach'] = i


        BV_global.reach = new_reach
        #remove_crossing_XS(BV_global)

    XS_lines_filepath = os.path.join(params.work_path, 'XS_lines.shp')
    save_XS_lines(BV_global, XS_lines_filepath)
    create_all_levee_lines(BV_global, params.work_path)
    print('Cross section created')

    if nochannel:
        createAllBankLines(BV_global)
        save_bank_lines(BV_global, params.work_path, 'all_banks')
        BV_global.display("Bank lines created")
        BV1 =BV_global


    #-------HYDRAULICS--------------------
    if not nochannel:
        config_cal = run_hydraulics(BV_global,params)


    if save:
        filename = save_BV_results(BV_global, params, config_cal)
        subgroups_types = {
            'reach': Reach,  # Le nom du groupe 'reach' correspond à la classe Reach
            'section': Section,  # Le nom du groupe 'section' correspond à la classe Section
            'Coord': Coord
        }
        with h5py.File(filename, 'r') as f:
        # Reconstruct the BV object using the read_object_from_hdf5 function
            root_group = f['Catchment']
            bv_obj = read_object_from_hdf5(root_group, ModelCatchment,subgroups_types)


    if post:

        export_map(BV_global, params, config_cal)

    #---BATHYMETRICS---------------------------------------------
    #-----------------------------------------------------------------------------
    if bathy:
        run_bathymetric(BV_global,params)

    return BV1

def select_XS_option(BV1,params):
    if not params['I']['XS_filepath']:

        BV1.interpolateReach(params['XS']['creation_step'])
        create_XS_lines(BV1, params)

        if params['XS']['optimize_XS']:
            if not params['I']['riverbanks_filepath'] and params['XS']['optimization_method'] == 'overbank':
                params['XS']['optimization_method'] = 'angle'
            if params['XS']['optimization_method'] == 'angle' or params['XS']['optimization_method'] == 'overbank' or \
                    params['XS']['optimization_method'] == 'bank':
                optimize_XS_lines(BV1, params, method=params['XS']['optimization_method'],
                                  max_iter=params['H']['MaxIter'], verbose=params.verbose)

        if params['XS']['width_from_banks'] and params['I']['riverbanks_filepath']:
            reduceXStobank(BV1, params['XS']['distSearchMin'], params['XS']['method_banks'])
        # remove_crossing_XS(BV1)
        if not BV1.init_mode in [11, 12]:
            project_XS_lines(BV1, params)
            create_all_centerlines(BV1, params.work_path)
        else:  # cas sans DEM ni XS file, création section plate avant creusement
            for reach in BV1.reach:
                reach.slope = []
                for ids, section in enumerate(reach.section_list):
                    section.originXSLocation(params['XS']['distSearchMin'])
                    reach.slope.append(params['B']['average_slope'])
                    section.slope = params['B']['average_slope']
                    section.geom = LineString([(x, y, 0) for x, y in zip(section.geom.xy[0], section.geom.xy[1])])

    else:
        import_XS_lines(BV1, params)
        if params['XS']['width_from_banks'] and params['I']['riverbanks_filepath']:
            reduceXStobank(BV1, params['XS']['distSearchMin'], params['XS']['method_banks'])

        # if not BV1.reach[0].section_list[0].geom.has_z:
        resampleXS(BV1, params)
        project_XS_lines(BV1, params)
        create_all_centerlines(BV1, params.work_path)
        nsection = 0

    if params['XS']['interpolate_XS']:
        interpolate_XS_lines(BV1, params)
        if params['XS']['width_from_banks'] and params['I']['riverbanks_filepath']:
            reduceXStobank(BV1, params['XS']['distSearchMin'], params['XS']['method_banks'])
        #remove_crossing_XS(BV1)


if __name__ == '__main__':
    # Execute when the module is not initialized from an import statement.
    # CLI argument parser
    parser = argparse.ArgumentParser(description='a CLI (command line interface) for CEPHEE')
    parser.add_argument('parameter_file', help='Provide parameter file',default=os.path.join(getcwd(),'core/Parameters.py'))
    parser.add_argument('--output_folder', help='Specify folder for output files', default=getcwd())
    parser.add_argument('--model', help='option for specific computation', default=None)
    parser.add_argument('--post', help='select creation of map results', default=False)
    parser.add_argument('--bathy', help='select bathymetric treatment', default=False)
    parser.add_argument('--save', help='select bathymetric treatment', default=False)
    args = parser.parse_args()


    # read input files
    if not path.isfile(args.parameter_file):
        raise SystemExit(args.parameter_file + ' file not found')

    params = read_param(args.parameter_file)
    BV = cephee_cli(params,args.model,args.post,args.bathy,nochannel =True, save=args.save)

