# Author: Cameron F. Abrams <cfa22@drexel.edu>

"""
Various string manipulation functions for ycleptic
"""
import yaml
from datetime import date
import sys
from . import __version__

banner_message="""
    Ycleptic v. {}
    https://ycleptic.readthedocs.io/en/latest/

    Cameron F. Abrams <cfa22@drexel.edu>

    """.format(__version__)

def raise_clean(ErrorInstance):
    """
    Raises an error with a clean message showing no traceback.

    Parameters
    ----------
    ErrorInstance: Exception instance
        The exception instance to raise.
    """
    try:
        raise ErrorInstance
    except ErrorInstance.__class__ as e:
        print(f"Error: {e}", file=sys.stderr)
        sys.exit(1)

def my_indent(text,indent=4):
    i=' '*indent
    return i+f'\n{i}'.join(text.split('\n'))

def dict_to_rst_yaml_block(data: dict) -> str:
    """ by ChatGPT 4o on 2025-06-15 """
    class LiteralString(str): pass

    def literal_str_representer(dumper, value):
        return dumper.represent_scalar('tag:yaml.org,2002:str', value, style='|')

    yaml.add_representer(LiteralString, literal_str_representer)

    def convert_multiline_strings(obj):
        if isinstance(obj, dict):
            return {k: convert_multiline_strings(v) for k, v in obj.items()}
        elif isinstance(obj, list):
            return [convert_multiline_strings(v) for v in obj]
        elif isinstance(obj, str) and '\n' in obj:
            return LiteralString(obj)
        else:
            return obj

    data = convert_multiline_strings(data)
    yaml_str = yaml.dump(data, sort_keys=False)

    # Indent each line by 3 spaces to comply with reST code block indentation
    indented_yaml = '\n'.join('   ' + line if line.strip() else '' for line in yaml_str.splitlines())

    return f".. code-block:: yaml\n\n{indented_yaml}"

def generate_footer(app_name=__package__, version=__version__, style="paragraph"):
    today = date.today().isoformat()
    if style == "comment":
        return f".. This file was generated by {app_name} v{version} on {today}."

    elif style == "rubric":
        return f"""
.. rubric:: Generated Documentation

*Created by {app_name} v{version} on {today}.*
""".strip()

    elif style == "paragraph":
        return f"""
----

This page was automatically generated by **{app_name}** v{version} on {today}.
""".strip()

    elif style == "note":
        return f"""
.. note::

   This file was automatically generated by *{app_name}* version {version} on {today}.
""".strip()
    elif style == "raw-html":
        return f"""
.. raw:: html

   <div class="autogen-footer">
     <p>This page was generated by {app_name} v{version} on {today}.</p>
   </div>
""".strip()
    else:
        raise ValueError(f"Unknown style '{style}'. Choose from 'comment', 'rubric', 'paragraph', or 'note'.")

def oxford(a_list,conjunction='or'):
    """
    Returns a string with the elements of a_list joined by commas, with the last element preceded by the conjunction.
    If a_list is empty, returns an empty string. If a_list has one element, returns that element. If a_list has two elements, returns them joined by the conjunction. If a_list has three or more elements, returns all elements joined by commas, with the last element preceded by the conjunction.

    Parameters
    ----------
    a_list : list of str
        List of strings to join.
    conjunction  : str
        The conjunction to use before the last element (default is 'or').

    Returns
    -------
    str
        A string with the elements of a_list joined by commas, with the last element preceded by the conjunction.
    """
    if not a_list: return ''
    if len(a_list)==1:
        return a_list[0]
    elif len(a_list)==2:
        return f'{a_list[0]} {conjunction} {a_list[1]}'
    else:
        return ", ".join(a_list[:-1])+f', {conjunction} {a_list[-1]}'