defmodule Livebook.Notebook.Export.ElixirTest do
  use ExUnit.Case, async: true

  alias Livebook.Notebook.Export
  alias Livebook.Notebook

  test "acceptance" do
    notebook = %{
      Notebook.new()
      | name: "My Notebook",
        sections: [
          %{
            Notebook.Section.new()
            | name: "Section 1",
              cells: [
                %{
                  Notebook.Cell.new(:markdown)
                  | source: """
                    Make sure to install:

                    * Erlang
                    * Elixir
                    * PostgreSQL\
                    """
                },
                %{
                  Notebook.Cell.new(:code)
                  | source: """
                    Enum.to_list(1..10)\
                    """
                },
                %{
                  Notebook.Cell.new(:markdown)
                  | source: """
                    This is it for this section.\
                    """
                }
              ]
          },
          %{
            Notebook.Section.new()
            | id: "s2",
              name: "Section 2",
              cells: [
                %{
                  Notebook.Cell.new(:code)
                  | source: """
                    IO.gets("length: ")\
                    """
                },
                %{
                  Notebook.Cell.new(:smart)
                  | source: """
                    IO.puts("My text")\
                    """,
                    attrs: %{"text" => "My text"},
                    kind: "text"
                }
              ]
          },
          %{
            Notebook.Section.new()
            | name: "Section 3",
              parent_id: "s2",
              cells: [
                %{
                  Notebook.Cell.new(:code)
                  | source: """
                    Process.info()\
                    """
                }
              ]
          }
        ]
    }

    expected_document = """
    # Run as: iex --dot-iex path/to/notebook.exs

    # Title: My Notebook

    # ── Section 1 ──

    # Make sure to install:

    # * Erlang
    # * Elixir
    # * PostgreSQL

    Enum.to_list(1..10)

    # This is it for this section.

    # ── Section 2 ──

    IO.gets("length: ")

    IO.puts("My text")

    # ── Section 3 ── (⎇ from Section 2)

    # Process.info()
    """

    document = Export.Elixir.notebook_to_elixir(notebook)

    assert expected_document == document
  end

  describe "setup cell" do
    test "includes the leading setup cell when it has content" do
      notebook =
        %{
          Notebook.new()
          | name: "My Notebook",
            sections: [%{Notebook.Section.new() | name: "Section 1"}]
        }
        |> Notebook.put_setup_cells([%{Notebook.Cell.new(:code) | source: "Mix.install([...])"}])

      expected_document = """
      # Run as: iex --dot-iex path/to/notebook.exs

      # Title: My Notebook

      Mix.install([...])

      # ── Section 1 ──
      """

      document = Export.Elixir.notebook_to_elixir(notebook)

      assert expected_document == document
    end
  end

  test "comments out non-elixir code cells" do
    notebook = %{
      Notebook.new()
      | name: "My Notebook",
        sections: [
          %{
            Notebook.Section.new()
            | name: "Section 1",
              cells: [
                %{
                  Notebook.Cell.new(:code)
                  | source: """
                    Enum.to_list(1..10)\
                    """
                },
                %{
                  Notebook.Cell.new(:code)
                  | language: :erlang,
                    source: """
                    lists:seq(1, 10).\
                    """
                }
              ]
          }
        ]
    }

    expected_document = """
    # Run as: iex --dot-iex path/to/notebook.exs

    # Title: My Notebook

    # ── Section 1 ──

    Enum.to_list(1..10)

    # lists:seq(1, 10).
    """

    document = Export.Elixir.notebook_to_elixir(notebook)

    assert expected_document == document
  end

  test "python" do
    notebook =
      %{
        Notebook.new()
        | name: "My Notebook",
          sections: [
            %{
              Notebook.Section.new()
              | name: "Section 1",
                cells: [
                  %{
                    Notebook.Cell.new(:code)
                    | language: :python,
                      source: """
                      range(0, 10)\
                      """
                  }
                ]
            }
          ]
      }
      |> Notebook.put_setup_cells([
        %{
          Notebook.Cell.new(:code)
          | source: """
            Mix.install([
              {:pythonx, "~> 0.4.2"}
            ])\
            """
        },
        %{
          Notebook.Cell.new(:code)
          | language: :"pyproject.toml",
            source: """
            [project]
            name = "project"
            version = "0.0.0"
            requires-python = "==3.13.*"
            dependencies = []\
            """
        }
      ])

    expected_document = ~S'''
    # Run as: iex --dot-iex path/to/notebook.exs

    # Title: My Notebook

    Mix.install([
      {:pythonx, "~> 0.4.2"}
    ])

    Pythonx.uv_init("""
    [project]
    name = "project"
    version = "0.0.0"
    requires-python = "==3.13.*"
    dependencies = []
    """)

    import Pythonx

    # ── Section 1 ──

    ~PY"""
    range(0, 10)
    """
    '''

    document = Export.Elixir.notebook_to_elixir(notebook)

    assert expected_document == document
  end
end
