import ast

def assign_last_line_into_variable(code):
    """Take the last command and assign it to a known variable name, if it's
    not already an assignment.

    If the command includes the "servable()" function call, remove it.

    Examples
    ========

    >>> code = "p = already_an_assignment(1, 2, kw1=True, kw2=False)"
    >>> assign_last_line_into_variable(code)
    p = already_an_assignment(1, 2, kw1=True, kw2=False)

    >>> code = "some_command(1, 2, kw1=True, kw2=False)"
    >>> assign_last_line_into_variable(code)
    mypanel = some_command(1, 2, kw1=True, kw2=False)

    >>> code = "some_other_command(1, 2, kw1=True, kw2=False).servable()"
    >>> assign_last_line_into_variable(code)
    mypanel = some_other_command(1, 2, kw1=True, kw2=False)

    """
    tree = ast.parse(code)
    ln = tree.body[-1]
    if isinstance(ln, ast.Assign):
        return code
    
    if isinstance(ln, ast.Expr):
        if (isinstance(ln.value, ast.Call) and
            isinstance(ln.value.func, ast.Attribute) and 
            (ln.value.func.attr == "servable")):
            # we are in this case: panel_obj.servable(). Remove servable()
            tree.body[-1] = ln.value.func.value
        
        # make an assignment
        value = tree.body[-1].value if isinstance(tree.body[-1], ast.Expr) else tree.body[-1]
        tree.body[-1] = ast.Assign(
            targets=[ast.Name(id="mypanel")], 
            value=value,
            lineno=tree.body[-1].lineno
        )
    return ast.unparse(tree)










# import re
# import textwrap

# import plotly


# INDENT_SPACES = " " * 3


# def save_plotly_figure(fig, path):
#     r"""
#     Save a Plotly figure.

#     Parameters
#     ----------
#     fig : plotly figure
#         A plotly figure to save.
#     path : str
#         A file path.

#     Returns
#     -------
#     None

#     Examples
#     --------
#     >>> import plotly.express as px
#     >>> import tempfile
#     >>> fig = px.scatter(x=[0, 1, 2, 3, 4], y=[0, 1, 4, 9, 16])
#     >>> path = tempfile.NamedTemporaryFile(suffix=".html").name
#     >>> save_plotly_figure(fig, path)
#     """
#     ext = path.split(".")[-1]
#     if ext in ["htm", "html"]:
#         fig_html = plotly.offline.plot(fig, output_type="div",
#             include_plotlyjs="cdn", auto_open=False)
#         with open(path, "w") as f:
#             f.write(fig_html)
#     else:
#         fig.write_image(path)


# def assign_last_line_into_variable(code, variable_name):
#     r"""
#     Save a Plotly figure.

#     Parameters
#     ----------
#     code : str
#         A string representing code.
#     name : str
#         A variable name.

#     Returns
#     -------
#     str
#         Mew code.

#     Examples
#     --------
#     >>> code = "a = 1\nfunc(a)"
#     >>> new_code = assign_last_line_into_variable(code, "b")
#     >>> print(new_code)
#     a = 1
#     b = func(a)
#     """
#     lines = code.split("\n")
#     for idx in range(len(lines) - 1, -1, -1):
#         if lines[idx].strip() != "":
#             lines[idx] = "{} = ".format(variable_name) + lines[idx]
#             break
#     return "\n".join(lines)


# def create_directive_block(name, arguments, options, content):
#     r"""
#     Create a directive block.

#     Parameters
#     ----------
#     name : str
#         A directive name.
#     arguments : list of str
#         Arguments of the directive.
#     option : dict
#         Option of the directive.
#     content : list of str
#         Content of the directive.

#     Returns
#     -------
#     str
#         A directive block.

#     Examples
#     --------
#     >>> block = create_directive_block(
#     ...     "plotly",
#     ...     ["f1", "f2"],
#     ...     {"a": 0, "b": 1},
#     ...     ["l1", "l2"],
#     ... )
#     >>> print(block)
#     .. plotly:: f1 f2
#        :a: 0
#        :b: 1
#     <BLANKLINE>
#        l1
#        l2
#     """
#     header = ".. {}:: ".format(name) + " ".join(arguments)
#     code = "\n".join(map(str, content))

#     lines = [header]

#     if len(options.items()) > 0:

#         def process_value(v):
#             if isinstance(v, list):
#                 return ", ".join(v)
#             return v

#         options_block = "\n".join(":{}: {}".format(k, process_value(v)) for k, v in options.items())
#         lines.append(textwrap.indent(options_block, INDENT_SPACES))

#     lines.append("")
#     lines.append(textwrap.indent(code, INDENT_SPACES))

#     return "\n".join(lines)


# def create_code_block(code, language=None):
#     return "\n".join(
#         [
#             ".. code-block::{}".format(" " + language if language else ""),
#             "",
#             textwrap.indent(code.strip(), INDENT_SPACES),
#             "",
#         ]
#     )


# def strip_last_line(code):
#     r"""
#     Strips the last line of the give code block

#     Parameters
#     ----------
#     code : str
#         Code to strip

#     Returns
#     -------
#     str:
#         Stripped code

#     Examples
#     --------
#     >>> strip_last_line("a")
#     ''
#     >>> strip_last_line("a\nb")
#     'a'
#     >>> strip_last_line("a\nb\nc")
#     'a\nb'
#     """
#     return "\n".join(code.strip().split("\n")[:-1])


# def ends_with_show(code):
#     r"""
#     Returns True if the last line of the given code block ends with `show()`

#     Parameters
#     ----------
#     code : str
#         Code that may contain a line that looks like `fig.show()`

#     Returns
#     -------
#     str:
#         Variable name of the object that calls `show()`

#     Examples
#     --------
#     >>> ends_with_show("fig.show()")  # simple
#     True
#     >>> ends_with_show("fig.show(1, a=2)")  # show with arguments
#     True
#     >>> ends_with_show("fig = dummy\nfig.show()\n")  # multiline
#     True
#     >>> ends_with_show("foo")  # doesn't contains `show`
#     False
#     """
#     # TODO: Use a more strict regular expression
#     pattern = r"^(.+)\.show\(.*\)$"
#     match = re.search(pattern, code.strip().split("\n")[-1], flags=re.DOTALL)
#     return bool(match)
