#!/usr/bin/env python3
# -*- coding: utf-8 -*-
import argparse
import sys
import traceback
from collections import defaultdict

try:
    import imaspy as imas
except ImportError:
    import imas
from packaging import version
from rich_argparse import RichHelpFormatter

from idstools.database import DBMaster
from idstools.utils.idshelper import get_available_ids_and_occurrences
from idstools.utils.idslogger import setup_logger

logger = setup_logger("module")
if __name__ == "__main__":
    # Management of input arguments
    parser = argparse.ArgumentParser(
        description="Copy IDSs from a data-entry into another one",
        formatter_class=RichHelpFormatter,
    )
    parser.add_argument(
        "-s",
        "--src",
        type=str,
        required=True,
        help="source uri",
    )
    parser.add_argument(
        "-d",
        "--dest",
        type=str,
        required=True,
        help="destination uri",
    )

    parser.add_argument(
        "-f",
        "--force",
        action="store_true",
        help="Force the creation of destination data-entry (existing data will be lost)",
    )
    parser.add_argument(
        "--set-dataset-version",
        action="store_true",
        help="(DEPRECATED) Store current DD version into dataset_description IDS if it exists. "
        "This option is deprecated and may be removed in the next major version.",
    )
    parser.add_argument(
        "-i",
        "--interactive",
        action="store_true",
        help="Prompt the user to overwrite the ids (Default is to overwrite the ids without asking)",
    )
    occgroup = parser.add_mutually_exclusive_group()
    occgroup.add_argument(
        "-a",
        "--all-occurrences",
        action="store_true",
        help="Copy all occurrences available in the source into the destination",
    )
    occgroup.add_argument(
        "-o",
        "--output-occurrence",
        type=int,
        default=None,
        help="Copy the selected source into the specified occurrence at the destination",
    )
    parser.add_argument(
        "--dd-update",
        action="store_true",
        help=(
            f"Convert IDS to the default Data Dictionary version "
            f"(={imas.ids_factory.IDSFactory().dd_version}, "
            f"otherwise use the original version stored on disk)"
        ),
    )
    parser.add_argument(
        "ids",
        nargs="*",
        type=str,
        help="IDSs to copy (leave empty to select all IDSs with default occurrence,"
        'or append "/n" to copy a specific occurrence "n")',
    )

    args = parser.parse_args()

    if args.src is not None and args.dest is not None:
        if args.src == args.dest:
            logger.error("Can not use the same uri as source and destination!")
            exit()

    inputargs = argparse.Namespace()
    inputargs.uri = args.src

    src_connection = DBMaster.get_connection(inputargs)
    availables_ids = get_available_ids_and_occurrences(src_connection)
    if args.ids == []:
        args.ids = [f"{ids}/{occ}" for ids, occ in availables_ids]

    if src_connection is None:
        logger.error("Error opening source pulse! Please check existence.")
        sys.exit()
    outputargs = argparse.Namespace()
    outputargs.uri = args.dest

    # hack to get underlying data dictionary version used by idses
    src_dd_version = src_connection.dd_version

    ids_dd_versions = {}
    for idsname, occurrence in availables_ids:
        try:
            _dummy = src_connection.get(idsname, lazy=True, autoconvert=False)
            ids_dd_versions[idsname] = _dummy.ids_properties.version_put.data_dictionary.value
        except Exception as e:
            pass

    ids_grouped_by_dd_version = defaultdict(list)
    for idsname, data_dictionary_version in ids_dd_versions.items():
        ids_grouped_by_dd_version[data_dictionary_version].append(idsname)
    if not args.dd_update:
        src_dd_version = max(ids_dd_versions.values(), key=version.parse)
        if len(args.ids) != 1 and len(set(ids_dd_versions.values())) > 1:
            ids_grouped_by_dd_version_output = ", ".join(
                f"{k}: {', '.join(v)}" for k, v in ids_grouped_by_dd_version.items()
            )
            logger.error(
                f"The source pulse contains IDSs with different data dictionary versions. \n\n"
                f"{ids_grouped_by_dd_version_output} \n\n"
            )
            exit(1)
    else:
        ids_grouped_by_dd_version_output = ", ".join(
            f"{k}: {', '.join(v)}" for k, v in ids_grouped_by_dd_version.items()
        )
        logger.warning(
            f"Be careful, all IDSs will be converted to data dictionary version {src_dd_version} using explicit "
            "conversion.Below is the list of IDSs grouped by data dictionary version: \n\n"
            f"{ids_grouped_by_dd_version_output} \n\n"
            f"This is still an experimental feature and may miss some type conversions."
            f"Please verify the conversion carefully using idsdiff."
        )

    if args.force:
        # CREATE DEST
        outputargs.mode = "w"
        dest_connection = None
        if outputargs.uri != "" and outputargs.uri is not None:
            dest_connection = imas.DBEntry(outputargs.uri, outputargs.mode, dd_version=src_dd_version)
        if dest_connection is None:
            logger.error("Error creating destination pulse! Please check parameters and permissions.")
            exit(1)
    else:
        outputargs.mode = "a"
        dest_connection = None
        if outputargs.uri != "" and outputargs.uri is not None:
            try:
                dest_connection = imas.DBEntry(outputargs.uri, outputargs.mode, dd_version=src_dd_version)
            except Exception as e:
                outputargs.mode = "w"
                dest_connection = imas.DBEntry(outputargs.uri, outputargs.mode, dd_version=src_dd_version)

        if dest_connection is None:
            logger.error("Error opening destination pulse! Please check parameters and permissions.")
            exit(1)

    if args.all_occurrences:
        if "/" in args.ids:
            logger.error("Please do not specify source occurrences together with -a/--allOccurrences option")
            exit(1)
        else:
            allids = []
            for idsname in args.ids:
                occurrence_list = src_connection.list_all_occurrences(idsname)
                allids.append(idsname)
                allids.extend(f"{idsname}/{o}" for o in occurrence_list if o != 0)
            args.ids = allids

    # COPY IDSs FROM SOURCE TO DEST
    for idsname in args.ids:
        inocc = 0
        idsid = idsname.split("/")
        if len(idsid) == 2:
            inocc = int(idsid[1])

        if args.interactive:
            dest_ids_object = None
            try:
                dest_ids_object = dest_connection.get(
                    idsid[0], occurrence=inocc, autoconvert=False, ignore_unknown_dd_version=True
                )
                if args.dd_update:
                    dest_ids_object = imas.convert_ids(dest_ids_object, dest_connection.factory.version)

            except Exception as e:
                logger.error(f"Exception occurred detailed description : {e}")
            if dest_ids_object:
                if dest_ids_object.ids_properties.homogeneous_time != imas.ids_defs.EMPTY_INT:
                    user_choice = ""
                    while user_choice not in ["y", "n"]:
                        user_choice = input(f"{idsid[0]} already exists, do you want to overwrite it (y/n)? :")
                    if user_choice == "n":
                        print(f"skip {idsid[0]}")
                        continue
        idsobj = None
        try:
            idsobj = src_connection.get(idsid[0], occurrence=inocc, autoconvert=False, ignore_unknown_dd_version=True)
            if args.dd_update:
                idsobj = imas.convert_ids(idsobj, src_connection.factory.version)
        except Exception as e:
            logger.error(f"Exception occurred, detailed error {e}")
        if idsobj:
            if args.set_dataset_version and idsid[0] == "dataset_description":
                if hasattr(idsobj, "dd_version"):
                    idsobj.dd_version = src_dd_version
            try:
                if idsobj.ids_properties.homogeneous_time != imas.ids_defs.EMPTY_INT:
                    print(f"Copying {idsname}")
                    outocc = inocc if args.output_occurrence is None else args.output_occurrence
                    dest_connection.put(idsobj, occurrence=outocc)
            except Exception as exc:
                traceback.print_exc()
                if not args.force:
                    logger.warning(
                        "This error could be due to difference of data dictionary version between the"
                        " current one and the existing destination pulse"
                    )
                    logger.warning(
                        "You can use option -f/--force to recreate the destination pulse with the current"
                        " DD version (WARNING: all other IDSs will be lost at dest)"
                    )

    src_connection.close()
    dest_connection.close()
