defmodule Api.Studies do
  import Ecto.Query
  alias Api.Repo
  require Logger

  def studies_sql_query(filters) do
    customfilter =
      case Map.get(filters, "customfilter") do
        nil -> dynamic([_], true)
        "" -> dynamic([_], true)
        expr ->
          case ExpressionParser.parse(expr) do
            {:ok, ast} ->
            ExpressionToEcto.to_dynamic(ast)
            {:error, _reason} -> raise "Error al parsear customfilter"
          end
      end

    page = filters["page"] || 1
    size = filters["size"] || 24

    filter = filters["filter"] || []
    sort = filters["sort"] || []

    Logger.info("sort -> #{inspect(sort)}")

    # Construcción de condiciones de filtro dinámicas
    filter_conditions =
      Enum.reduce(filter, dynamic(true), fn f, acc ->
        field = f["field"]
        value = f["value"]

        condition =
          case field do
            "modality" ->
              dynamic([s], ilike(s.modality, ^"%#{value}%"))

            "idstudy" ->
              dynamic([s], like(fragment("CAST(? AS TEXT)", s.idstudy), ^"#{value}%"))

            "studydate" ->
              dynamic([s], fragment("CAST(? AS DATE)::text LIKE ?", s.studydate, ^"%#{value}%"))

            "studydate_start" ->
              if value == "" do
                dynamic(true)
              else
                dynamic([s], fragment("CAST(? AS DATE)::text", s.studydate) >= ^value)
              end

            "studydate_end" ->
              if value == "" do
                dynamic(true)
              else
                dynamic([s], fragment("CAST(? AS DATE)::text", s.studydate) <= ^value)
              end

            "accessionnumber" ->
              dynamic([s], ilike(s.accessionnumber, ^"%#{value}%"))

            "proceduredescription" ->
              dynamic([s], ilike(s.studydescription, ^"%#{value}%"))

            "insurer" ->
              dynamic([s], ilike(s.insurer, ^"%#{value}%"))

            "sitename" ->
              dynamic([s], ilike(s.institutionname, ^"%#{value}%"))

            "nrodocumento" ->
              dynamic([s, p], ilike(p.patientid, ^"%#{value}%"))

            "patientname" ->
              dynamic([s, p], ilike(p.patientname, ^"%#{value}%"))

            "region" ->
              dynamic([s], s.region == ^value)

            "studytime" ->
              dynamic([s], fragment("CAST(? AS TIME)::text LIKE ?", s.studytime, ^"#{value}%"))

            _ ->
              dynamic(true)
          end

        # Combina las condiciones dinámicas
        dynamic([s, p], ^condition and ^acc)
      end)

    sort_conditions =
      if Enum.empty?(filters["sort"]) do
        [{:desc, :studydate}]
      else
        Enum.map(filters["sort"], fn v ->
          direction = String.to_atom(v["dir"])
          field = String.to_atom(v["field"])

          {direction, field}
        end)
      end

    Logger.info("sort_conditions --> #{inspect(sort_conditions)}")

    combined_filter =
      dynamic([q], ^filter_conditions and ^customfilter)

      query =
        from s in "study",
          join: p in "patient",
          on: p.idpatient == s.idpatient,
          left_join: sr in "studyreport",
          on: sr.idstudy == s.idstudy,
          left_join: st in "statuses",
          on: st.idstatus == sr.idstudyreport,
          where: ^combined_filter,
          select: %{
            recordstotal: fragment("count(*) over()"),
            idstudy: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", s.idstudy),
            #idstudy: s.idstudy,
            accessionnumber: s.accessionnumber,
            studydate: s.studydate,
            studytime: s.studytime,
            patientname: fragment("select replace(?, '^', ' ')", p.patientname),
            proceduredescription: s.studydescription,
            modality: s.modality,
            sitename: s.institutionname,
            insurer: s.insurer,
            nrodocumento: fragment("substring(encrypt(?::text::bytea, '1nf0rm3', 'aes')::text from 3)", p.patientid),
            #nrodocumento: p.patientid,
            hasaudio: fragment("CASE WHEN ? IS NOT NULL THEN true ELSE false END", s.audiofile)
          },
          order_by: ^sort_conditions,
          limit: ^size,
          offset: ^((page - 1) * size)


    result = Repo.one(
      from q in subquery(query),
      group_by: q.recordstotal,
      select: %{
        data: fragment("json_agg(?)::text", q),
        recordstotal: q.recordstotal
      }
    )

    case result do
      nil ->
        %{data: [], last_page: 0}

      result ->
        # Calcula last_page
        last_page = div(result.recordstotal + size - 1, size)
        %{data: Jason.decode!(result.data), last_page: last_page}
    end

  end
end
