defmodule ExpressionToEcto do
  import Ecto.Query

  def to_dynamic([]), do: true

  def to_dynamic([single]), do: build_dynamic(single)

  def to_dynamic(ast), do: build_dynamic(ast)

  # Operadores lógicos
  defp build_dynamic({:or, left, right}) do
    dynamic([q], ^build_dynamic(left) or ^build_dynamic(right))
  end

  defp build_dynamic({:and, left, right}) do
    dynamic([q], ^build_dynamic(left) and ^build_dynamic(right))
  end

  # Comparaciones con número
  defp build_dynamic({:comparison, [{:field, field}, op, {:number, val}]}) do
    field_atom = String.to_atom(field)

    case op do
      :== -> dynamic([q], field(q, ^field_atom) == ^val)
      :!= -> dynamic([q], field(q, ^field_atom) != ^val)
      :>  -> dynamic([q], field(q, ^field_atom) > ^val)
      :<  -> dynamic([q], field(q, ^field_atom) < ^val)
      :>= -> dynamic([q], field(q, ^field_atom) >= ^val)
      :<= -> dynamic([q], field(q, ^field_atom) <= ^val)
      other -> raise "Operador no soportado: #{inspect(other)}"
    end
  end

  # Comparaciones con string
  defp build_dynamic({:comparison, [{:field, field}, op, {:string, val}]}) when op in [:==, :!=] do
    field_atom = String.to_atom(field)
      case op do
        :== -> dynamic([q], field(q, ^field_atom) == ^val)
        :!= -> dynamic([q], field(q, ^field_atom) != ^val)
      end
  end

  #  ILIKE
  defp build_dynamic({:comparison, [{:field, field}, :ilike, {:string, val}]}) do
    field_atom = String.to_atom(field)
    pattern = "#{val}"
    dynamic([q], ilike(field(q, ^field_atom), ^pattern))
  end

  # IN
  defp build_dynamic({:comparison, [{:field, field}, :in, {:list, vals}]}) when is_list(vals) do
    field_atom = String.to_atom(field)

    parsed_vals =
      Enum.map(vals, fn
        {:string, val} -> val
        {:number, val} -> val
        other -> raise "Tipo de dato no soportado en IN: #{inspect(other)}"
      end)

    dynamic([q], field(q, ^field_atom) in ^parsed_vals)
  end


  defp build_dynamic(other) do
    raise "AST no soportado o mal formado: #{inspect(other)}"
  end
end
