import logging


def left_merge_dataframe_on_validated_join_keys(left_df, right_df, join_keys):
    """Merge two dataframes together or return just the left_df if the right df is None

    Args:
        left_df: valid dataframe with join keys of matching data type (will be validated)
        right_df: None or valid dataframe with join keys of matching data type (will be validated)
        join_keys: list of keys to be validated on datatype and existance in left/right

    Returns:
        joined dataframe object
    """
    if right_df is None:

        initial_data_length = len(left_df)
        logging.info("Initial data length: {}".format(initial_data_length))

        return left_df

    else:

        initial_data_length = len(left_df)

        for j in join_keys:

            if not j in left_df.columns:
                raise Exception(
                    "Join key {} not in left {}. Aborting merge.".format(
                        j, left_df.columns
                    )
                )
            elif not j in right_df.columns:
                raise Exception(
                    "Join key {} not in right {}. Aborting merge.".format(
                        j, right_df.columns
                    )
                )

            if not left_df[j].dtype == right_df[j].dtype:
                logging.info(
                    "Join key {} is not of type {}. Casting.".format(
                        j, right_df[j].dtype
                    )
                )
                try:
                    right_df[j] = right_df[j].astype(left_df[j].dtype)
                except:
                    raise Exception(
                        "Cannot cast join key {} as {}".format(j, left_df[j].dtype)
                    )

        left_df = left_df.merge(right_df, on=join_keys, how="left")
        left_df.reset_index(inplace=True, drop=True)

        if len(left_df) > initial_data_length:
            logging.warning(
                "Merge increased data size by {} rows.".format(
                    len(left_df) - initial_data_length
                )
            )

        return left_df