# SPDX-License-Identifier: Apache-2.0
# SPDX-FileCopyrightText: 2025 DBVisor

defmodule Mix.Tasks.Sql.Get do
  use Mix.Task
  import SQL
  import Mix.Generator
  @moduledoc since: "0.3.0"

  @shortdoc "Generates a sql.lock"
  def run(args) do
    app = Mix.Project.config()[:app]
    Application.load(app)
    repos = Application.get_env(app, :ecto_repos)
    Mix.Task.run("app.config", args)
    Application.ensure_all_started(:ecto_sql, :permanent)
    lock = Enum.reduce(repos, [], fn repo, acc ->
      repo.__adapter__().ensure_all_started(repo.config(), [])
      repo.start_link(repo.config())
      get(repo)++acc
    end)
    create_file("sql.lock", lock_template(lock: lock), force: true)
  end

  defp get(repo) do
    sql = to_query(repo.__adapter__())
    {:ok, %{columns: columns, rows: rows}} = repo.query(sql.string, sql.params)
    columns = Enum.map(columns, &String.to_atom(String.downcase(&1)))
    Enum.map(rows, &Map.new(Enum.zip(columns, &1)))
  end

  defp to_query(value) when value in [Ecto.Adapters.Postgres, Postgrex], do: ~SQL"select * from information_schema.columns where table_schema not in ('information_schema', 'pg_catalog')"
  defp to_query(value) when value in [Ecto.Adapters.Tds, Tds], do: ~SQL"select * from information_schema.columns where table_schema not in ('information_schema', 'pg_catalog')"
  defp to_query(value) when value in [Ecto.Adapters.MyXQL, MyXQL], do: ~SQL"select * from information_schema.columns where table_schema not in ('mysql', 'performance_schema', 'sys')"
  defp to_query(value) when value in [Ecto.Adapters.SQLite3, Exqlite], do: ~SQL"select * from sqlite_master join pragma_table_info (sqlite_master.name)"

  embed_template(:lock, """
    %{
      columns: <%= inspect @lock, pretty: true, limit: :infinity %>,
      validate: fn
      <%= for %{table_name: table, column_name: column} <- @lock do %>
        <%= inspect String.to_charlist(table) %>, nil -> true
        <%= inspect String.to_charlist(table) %>, <%= inspect String.to_charlist(column) %> -> true
      <% end %>
      _, _ -> false
      end
    }
  """)
end
