defmodule OutlookWeb.TranslationLive.FormComponent do
  use OutlookWeb, :live_component

  alias Outlook.{Translations,InternalTree}
  alias Outlook.InternalTree.{TranslationUnit,Html}

  @impl true
  def render(assigns) do
    ~H"""
    <div class="flex gap-8 max-h-fit">
      <div class="basis-1/2 overflow-auto">
        <.header>
          <%= @title %>
          <:subtitle>Use this form to manage translation records in your database.</:subtitle>
        </.header>

        <.simple_form
          :let={f}
          for={@changeset}
          id="translation-form"
          phx-target={@myself}
          phx-change="validate"
          phx-submit="save"
        >
          <.input field={{f, :article_id}} type="hidden" />
          <.input field={{f, :language}} type="select" label="language"
              options={Application.get_env(:outlook,:deepl)[:target_langs]} />
          <.input field={{f, :title}} type="text" label="title" />
          <.input field={{f, :teaser}} type="textarea" label="teaser" class="h-28" />
          <.input field={{f, :date}} type="datetime-local" label="date" />
          <div class="flex items-center justify-between">
            <.input field={{f, :public}} type="checkbox" label="public" />
            <.input field={{f, :unauthorized}} type="checkbox" label="unauthorized" />
          </div>
          <input type="hidden" id="continue_edit" name="continue_edit" value="false" />
          <input type="hidden" id="publish" name="publish" value="false" />
          <:actions>
            <.button phx-click={JS.set_attribute({"value", "false"}, to: "#continue_edit") |> JS.set_attribute({"value", "false"}, to: "#publish")}
               phx-disable-with="Saving...">Save Translation</.button>
            <.button phx-click={JS.set_attribute({"value", "false"}, to: "#continue_edit") |> JS.set_attribute({"value", "true"}, to: "#publish")}
               phx-disable-with="Saving...">Save and Publish</.button>
            <.button phx-click={JS.set_attribute({"value", "true"}, to: "#continue_edit") |> JS.set_attribute({"value", "false"}, to: "#publish")}
               phx-disable-with="Saving...">Save and Edit</.button>
          </:actions>
        </.simple_form>
        <.tunit_editor current_tunit={@current_tunit} target={@myself} />
      </div>
      <div class="article basis-1/2 max-h-screen overflow-auto">
        <.button phx-disable-with="Translating..." phx-click="translate-deepl" phx-target={@myself}
          data-confirm-not="Are you sure? All previously translated text will be lost.">Translate with Deepl</.button>
        <progress :if={@deepl_progress} max="100" value={@deepl_progress} />
        <.render_doc tree={@article_tree} />
      </div>
    </div>
    """
  end

  @impl true
  def update(%{translation: translation} = assigns, socket) do
    changeset = Translations.change_translation(translation)

    {:ok,
     socket
     |> assign(assigns)
     |> assign(:current_tunit, %TranslationUnit{status: nil})
     |> assign(:changeset, changeset)
     |> assign_article_tree(translation)
     |> assign(:deepl_progress, nil)}
  end

  def update(%{progress: progress}, socket) do
    {:ok, socket |> assign(deepl_progress: progress)}
  end

  def update(%{deepl_translation: translation}, socket) do
    tunit_keys = Map.keys(socket.assigns.translation_content)
    case Outlook.Translators.process_translation_result(translation, tunit_keys, socket.assigns.current_user) do
      {:ok, new_translation_content} ->
        {:ok, socket
          |> assign(translation_content: new_translation_content)
          |> update_current_tunit(socket.assigns.current_tunit.status)}
      {:error, message} ->
        {:ok, socket |> put_flash(:error, message)}
    end
  end

  @impl true
  def handle_event("translate-deepl", _, socket) do
    Outlook.Translators.translate(socket.assigns.translation, socket.assigns.current_user)
    {:noreply, socket}
  end

  def handle_event("validate", %{"translation" => translation_params}, socket) do
    changeset =
      socket.assigns.translation
      |> Translations.change_translation(translation_params)
      |> Map.put(:action, :validate)

    {:noreply, assign(socket, :changeset, changeset)}
  end

  def handle_event("save", %{"translation" => translation_params} = params, socket) do
    socket = socket
    |> update_translation_with_current_tunit(socket.assigns.current_tunit.status)
    params = %{params |
      "translation" => Map.put(
        translation_params,
        "content",
        socket.assigns.translation_content
        )
        |> publish(params, socket)
      }
    save_translation(socket, socket.assigns.action, params)
  end

  def handle_event("tunit_status", %{"status" => status}, socket) do
    tunit = %TranslationUnit{socket.assigns.current_tunit | status: String.to_atom(status)}
    {:noreply, socket |> assign(:current_tunit, tunit)}
  end

  def handle_event("select_current_tunit", %{"nid" => nid}, socket) do
    {:noreply,
      socket
      |> update_translation_with_current_tunit(socket.assigns.current_tunit.status)
      |> assign(:current_tunit, socket.assigns.translation_content[nid])}
  end

  @doc "updating on browser events"
  def handle_event("update_current_tunit", %{"content" => content}, socket) do
    tunit = %TranslationUnit{socket.assigns.current_tunit | content: content}
    {:noreply, socket |> assign(:current_tunit, tunit)}
  end


  # updating after Deepl translation
  defp update_current_tunit(socket, nil), do: socket
  defp update_current_tunit(socket, _) do
    assign(socket,
      :current_tunit,
      socket.assigns.translation_content[socket.assigns.current_tunit.nid])
  end

  defp assign_article_tree(socket, translation) do
     socket
     |> assign(
      :article_tree,
      InternalTree.add_phx_click_event(translation.article.content,
        nodes: :tunits,
        click: "select_current_tunit",
        target: socket.assigns.myself)
      |> InternalTree.garnish(%{tunits: %{class: "tunit"}}))
  end

  defp update_translation_with_current_tunit(socket, nil), do: socket
  defp update_translation_with_current_tunit(socket, _) do
    socket
    |> assign(:translation_content,
      socket.assigns.translation_content
      |> Map.put(socket.assigns.current_tunit.nid, socket.assigns.current_tunit))
  end

  defp save_translation(socket, :edit, %{"translation" => translation_params} = params) do
    case Translations.update_translation(socket.assigns.translation, translation_params) do
      {:ok, _translation} ->
        {:noreply,
         socket
         |> put_flash(:info, "Translation updated successfully")
         |> continue_edit(:edit, params)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, :changeset, changeset)}
    end
  end

  defp save_translation(socket, :new, %{"translation" => translation_params} = params) do
    case Translations.create_translation(translation_params) do
      {:ok, translation} ->
        {:noreply,
         socket
         |> put_flash(:info, "Translation created successfully")
         |> continue_edit(:new, Map.put(params,"id", translation.id))}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign(socket, changeset: changeset)}
    end
  end

  defp continue_edit(socket, :edit, %{"continue_edit" => "true"}) do
    socket
  end
  defp continue_edit(socket, :new, %{"continue_edit" => "true"} = params) do
    socket |> push_patch(to: ~p(/translations/#{params["id"]}/edit))
  end
  defp continue_edit(socket, _, %{"continue_edit" => "false"}) do
    socket |> push_navigate(to: socket.assigns.navigate)
  end

  defp publish(translation_params, %{"publish" => "true"}, socket) do
    translation_params
    |> Map.put("public_content",
      InternalTree.render_public_content(
        socket.assigns.translation.article.content,
        socket.assigns.translation_content,
        socket.assigns.translation.language
        )
      )
  end
  defp publish(translation_params, %{"publish" => "false"}, _) do
    translation_params
  end
end
