#!python
import logging
import os
import argparse
import importlib
import json
from pathlib import Path

parser = argparse.ArgumentParser('Convert files between HESTIA format and other formats.')
parser.add_argument('--input-file', type=str,
                    help='Input file')
parser.add_argument('--output-folder', type=str, required=True,
                    help='Output files folder')
parser.add_argument('--input-format', type=str, required=True,
                    choices=['HESTIA', 'CoolFarm', 'OpenLCA', 'Klim'],
                    help='Input file format')
parser.add_argument('--output-format', type=str, required=True,
                    choices=['HESTIA', 'SimaPro', 'OpenLCA', 'LSRS'],
                    help='Output file format')
parser.add_argument('--mapping-files-directory', type=str, default='hestia-flowmaps',
                    help='Folder containing the mapping files in .csv format')
parser.add_argument('--skip-existing', action='store_true',
                    help='Do not overwrite existing converted file.')
parser.add_argument('--verbose', action='store_true',
                    help='Enables verbose mode.')
parser.add_argument('--debug-file', action='store_true',
                    help='Outputs conversion logs to debug file.')
parser.add_argument('--filter-by-name', type=str, nargs='+', default=[],
                    help='Optional list of names to filter results on. Must be in quotes. Can be used multiple times.')

# HESTIA specific arguments
parser.add_argument('--hestia-impact-id', type=str, nargs='+',
                    help='Run conversion from HESTIA ImpactAssessment.')

# SimaPro specific arguments
parser.add_argument('--simapro-output-process-type', default='System',
                    choices=['System', 'Unit process'],
                    help='The type of SimaPro process to generate.')

parser.add_argument('--simapro-preferred-simapro-libraries',
                    type=str, nargs='+',
                    help='List of SimaPro Library names to use when replacing HESTIA terms with SimaPro processes. '
                         'The converter will prioritize libraries in the order listed on the command line. '
                         'The name of the libraries must exactly match the names found in the flowmap files in the '
                         '"TargetListName" columns. '
                         'These flowmap rows always have "simapro_process_name" in the "TargetFlowContext" column.')

parser.add_argument('--simapro-map-water-use-to-irrigation-processes',
                    default=False,
                    action='store_true',
                    help='Replaces HESTIA terms of termtype "water" with Simapro library irrigation processes when '
                         'the input HESTIA cycle has used irrigation.')

parser.add_argument('--simapro-override-default-emission-compartment',
                    default=False,
                    action='store_true',
                    help='Rewrites all "Emissions to air/(unspecified)" emission compartments to '
                         '"Emissions to air/low. pop."')

parser.add_argument('--simapro-naming-convention',
                    default="default",
                    choices=['default', 'INRAE'],
                    help='Uses the INRAE naming convention for process names')

parser.add_argument('--simapro-create-dummy-processes',
                    default=True,
                    action='store_true',
                    help='When used with --simapro-output-process-type "Unit process", will turn inputs that '
                         'have no known equivalent Simapro process into a new "Dummy" process.')

parser.add_argument('--simapro-guess-country-for-certain-inputs',
                    default=False,
                    action='store_true',
                    help='Regionalise certain Inputs such as irrigation and electricity if country information is '
                         'missing on a per Input node basis.')

parser.add_argument('--simapro-convert-linked-impact-assessment',
                    default=False,
                    action='store_true',
                    help='Will also download and convert any HESTIA impact assessments referenced in a cycle Input. '
                         'The new SimaPro Unit process file will be saved to a new folder called '
                         '"referenced_processes".'
                         'The referenced files must be imported into SimaPro before the file that require them.')

parser.add_argument('--simapro-hestia-term-ids-to-save-as-dummies',
                    type=str, nargs='+',
                    help="When no flowmap is available for a given HESTIA term, we can still save the information "
                         "related to a `Cycle` `Input` as a 'Dummy' Simapro process.")
# OpenLCA specific arguments
parser.add_argument('--openlca-rescale-impact-assessment-to-amount', default=1,
                    help='Rescale all values for a new value of Product > value amount.')

args = parser.parse_args()


def _load_hestia_impact(id: str):
    from hestia_earth.converters.base.pydantic_models.hestia.hestia_file_tools import load_hestia_model_from_id
    return load_hestia_model_from_id(id)


def _load_impacts_from_zip_file(filepath: str):
    if args.input_format == 'HESTIA':
        from hestia_earth.converters.base.pydantic_models.hestia.hestia_file_tools import (
            extract_impact_assessments_from_zip_file
        )
        return extract_impact_assessments_from_zip_file(filepath)

    if args.input_format == 'OpenLCA':
        from hestia_earth.converters.openlca.pydantic_models.openlca_file_tools import load_from_zip_file
        return load_from_zip_file(filepath)

    if args.input_format == 'Klim':
        from hestia_earth.converters.klim.klim_to_hestia.file_tools import load_from_zip_file
        return load_from_zip_file(filepath)

    raise Exception(f"Loading ZIP file not supported for format: {args.input_format}")


def _load_hestia_from_jsonld_file(filepath: Path) -> list:
    from hestia_earth.converters.base.pydantic_models.hestia.hestia_file_tools import load_hestia_model_from_file
    return [load_hestia_model_from_file(filepath.parent, filepath)]


def _load_data_from_hestia():
    if args.hestia_impact_id:
        if isinstance(args.hestia_impact_id, list):
            return [_load_hestia_impact(h_id) for h_id in args.hestia_impact_id]
        return [_load_hestia_impact(args.hestia_impact_id)]
    if args.input_file and args.input_file.endswith('.zip'):
        return _load_impacts_from_zip_file(args.input_file)
    elif args.input_file and args.input_file.endswith('.jsonld'):
        return _load_hestia_from_jsonld_file(Path(args.input_file))
    raise Exception("Cannot load HESTIA input data.")


def _download_flowmaps_if_required():
    folder = args.mapping_files_directory
    if not os.path.exists(folder):
        logging.error('Flowmaps directory not found, downloading latest available')
        from hestia_earth.converters.utils.flowmaps import download_flowmaps
        download_flowmaps(folder)


def main():
    converter_namespace = next((v for v in [
        args.input_format.lower(),
        args.output_format.lower(),
    ] if v != 'hestia'), None)
    try:
        converter = importlib.import_module(
            f"hestia_earth.converters.{converter_namespace}.{args.input_format.lower()}_to_{args.output_format.lower()}.convert"
        ).convert
    except ModuleNotFoundError:
        raise Exception(f"Please install 'hestia-converters[{converter_namespace}]' first.")

    _download_flowmaps_if_required()

    data = None

    if args.input_format == 'HESTIA':
        data = _load_data_from_hestia()
    elif args.input_file.endswith('.zip'):
        data = _load_impacts_from_zip_file(args.input_file)
    else:
        try:
            with open(args.input_file, 'r') as f:
                data = json.load(f)
        except Exception:
            pass

    if not data:
        raise Exception(f"Could not load data from {args.input_format} format.")

    converter(data, **vars(args))


if __name__ == "__main__":
    main()
