lib/glific/clients/sol.ex

defmodule Glific.Clients.Sol do
  @moduledoc """
  Tweak GCS Bucket name based on group that the contact is in (if any)
  """

  import Ecto.Query, warn: false

  alias Glific.{
    Contacts,
    Partners,
    Partners.OrganizationData,
    Repo,
    Sheets.ApiClient
  }

  @doc """
  In the case of SOL we retrive the name of the contact is in and store
  and set the remote name to be a sub-directory under that name
  We add a contact id suffix to prevent name collisions
  """
  @spec gcs_file_name(map()) :: String.t()
  def gcs_file_name(media) do
    {:ok, contact} =
      Repo.fetch_by(Contacts.Contact, %{
        id: media["contact_id"],
        organization_id: media["organization_id"]
      })

    message_media = Glific.Messages.get_message_media!(media["id"])

    city = get_in(contact.fields, ["city", "value"]) || "unknown_city"
    _school_name = get_in(contact.fields, ["school_name", "value"]) || "unknown_school_name"
    student_name = get_in(contact.fields, ["contact_name", "value"]) || "unknown_student_name"
    caption = message_media.caption || ""

    _organization_name =
      get_in(contact.fields, ["organization_name", "value"]) || "unknown_organization_name"

    current_time = :os.system_time(:millisecond)

    folder = "#{city}/#{contact.phone}/#{student_name}"

    extension = get_extension(media["type"])

    file_name = "#{contact.phone}_#{city}_#{student_name}_#{caption}_#{current_time}.#{extension}"

    "#{folder}/#{file_name}"
  end

  @doc """
  Create a webhook with different signatures, so we can easily implement
  additional functionality as needed
  """
  @spec webhook(String.t(), map()) :: map()
  def webhook("fetch_activity", fields) do
    organization_id = Glific.parse_maybe_integer!(fields["organization_id"])
    language_label = fields["language_label"]
    city = fields["city"]
    ## y-m-d
    activity_date = Timex.today() |> Timex.format!("{YYYY}-{0M}-{0D}")
    activity = get_activity_by_date(organization_id, activity_date, city)
    activity_data = get_activity_content(activity, language_label, organization_id)

    activity_data =
      Map.merge(
        activity_data,
        %{
          city: city,
          activity_date: activity_date,
          artform_lable: "artform_start_#{activity_data[:artform]}_artform_ended",
          activity_name_label: "activity_name_start_#{activity_data[:name]}_activity_name_ended"
        }
      )

    if activity_data[:content] in [nil, ""],
      do: Map.put(activity_data, :error, "Something went worng."),
      else: Map.put(activity_data, :error, false)
  end

  def webhook("load_schedule", fields) do
    organization_id = Glific.parse_maybe_integer!(fields["organization_id"])
    load_activity_schedule(organization_id)
    %{completed: true}
  end

  def webhook("load_language_activities", fields) do
    organization_id = Glific.parse_maybe_integer!(fields["organization_id"])
    organization = Partners.organization(organization_id)

    Enum.each(organization.languages, fn language ->
      language.label
      |> String.downcase()
      |> load_language_activities(organization_id)
    end)

    %{completed: true}
  end

  @doc false
  @spec load_activity_schedule(non_neg_integer()) ::
          {:ok, OrganizationData.t()} | {:error, Ecto.Changeset.t()}
  def load_activity_schedule(org_id) do
    {key, url} = form_key_and_url("activity_schedule")

    ApiClient.get_csv_content(url: url)
    |> Enum.reduce(%{}, fn {_, row}, acc ->
      activity_slug = Glific.string_clean(row["Activity name in English"])
      row = Map.put(row, "activity_slug", activity_slug)
      date = row["Date"]
      city = row["City"]

      if Map.has_key?(acc, date),
        do: Map.put(acc, date, Map.put(acc[date], city, row)),
        else: Map.put(acc, date, Map.put(%{}, city, row))
    end)
    |> then(fn activity_schedule ->
      Partners.maybe_insert_organization_data(key, activity_schedule, org_id)
    end)
  end

  @spec load_language_activities(String.t(), non_neg_integer()) ::
          {:ok, OrganizationData.t()} | {:error, Ecto.Changeset.t()}
  defp load_language_activities(language_label, org_id) do
    {key, url} = form_key_and_url("activities_#{language_label}")

    ApiClient.get_csv_content(url: url)
    |> Enum.reduce(%{}, fn {_, row}, acc ->
      activity_slug = Glific.string_clean(row["Name of the Activity"])
      row = Map.put(row, "activity_slug", activity_slug)
      Map.put(acc, activity_slug, row)
    end)
    |> then(fn activity_data ->
      Partners.maybe_insert_organization_data(key, activity_data, org_id)
    end)
  end

  @spec form_key_and_url(String.t()) :: {String.t(), String.t()}
  defp form_key_and_url(key) do
    key = "sol_#{key}"
    url = "https://storage.googleapis.com/sheet-automation/#{key}.csv"
    {key, url}
  end

  @spec get_activity_by_date(non_neg_integer(), String.t(), String.t()) :: map()
  defp get_activity_by_date(organization_id, date, city) do
    {key, _url} = form_key_and_url("activity_schedule")

    {:ok, org_data} =
      Repo.fetch_by(OrganizationData, %{
        organization_id: organization_id,
        key: key
      })

    get_in(org_data.json, [date, city])
  end

  @spec get_activity_content(map(), String.t(), non_neg_integer()) :: map()
  defp get_activity_content(activity, language_label, organization_id) do
    language_label = String.downcase(language_label)
    {key, _url} = form_key_and_url("activities_#{language_label}")

    {:ok, org_data} =
      Repo.fetch_by(OrganizationData, %{
        organization_id: organization_id,
        key: key
      })

    activity_content = Map.get(org_data.json, activity["activity_slug"])

    %{
      name: activity_content["Name of the Activity"],
      artform: activity_content["Type of Activity"],
      content: activity_content["Content of the Activty"],
      poster_attachment: activity_content["Poster GCS Link"],
      audio_attachment: activity_content["Audio Recording GCS Link"],
      activity_meta: activity,
      activity_slug: activity["activity_slug"]
    }
  end

  defp get_extension(type) do
    cond do
      type in ["audio"] -> "mp3"
      type in ["video"] -> "mp4"
      type in ["image"] -> "png"
      type in ["document"] -> "pdf"
      true -> "png"
    end
  end
end