defmodule PlausibleWeb.GoogleAnalyticsController do
  use PlausibleWeb, :controller

  alias Plausible.Google
  alias Plausible.Imported
  use Plausible

  require Plausible.Imported.SiteImport

  plug(PlausibleWeb.RequireAccountPlug)

  plug(PlausibleWeb.Plugs.AuthorizeSiteAccess, [:owner, :editor, :admin, :super_admin])

  def property_form(
        conn,
        %{
          "access_token" => access_token,
          "refresh_token" => refresh_token,
          "expires_at" => expires_at
        } = params
      ) do
    site = conn.assigns.site

    redirect_route = Routes.site_path(conn, :settings_imports_exports, site.domain)

    result = Google.API.list_properties(access_token)

    error =
      case params["error"] do
        "no_data" ->
          "No data found. Nothing to import."

        "no_time_window" ->
          "Imported data time range is completely overlapping with existing data. Nothing to import."

        _ ->
          nil
      end

    case result do
      {:ok, properties} ->
        conn
        |> assign(:skip_plausible_tracking, true)
        |> render("property_form.html",
          access_token: access_token,
          refresh_token: refresh_token,
          expires_at: expires_at,
          site: conn.assigns.site,
          properties: properties,
          selected_property_error: error
        )

      {:error, :rate_limit_exceeded} ->
        conn
        |> put_flash(
          :error,
          "Google Analytics rate limit has been exceeded. Please try again later."
        )
        |> redirect(to: redirect_route)

      {:error, {:authentication_failed, message}} ->
        default_message =
          "We were unable to authenticate your Google Analytics account. Please check that you have granted us permission to 'See and download your Google Analytics data' and try again."

        message =
          if ce?() do
            message || default_message
          else
            default_message
          end

        conn
        |> put_flash(:ttl, :timer.seconds(5))
        |> put_flash(:error, message)
        |> redirect(to: redirect_route)

      {:error, :timeout} ->
        conn
        |> put_flash(
          :error,
          "Google Analytics API has timed out. Please try again."
        )
        |> redirect(to: redirect_route)

      {:error, _any} ->
        conn
        |> put_flash(
          :error,
          "We were unable to list your Google Analytics properties. If the problem persists, please contact support for assistance."
        )
        |> redirect(to: redirect_route)
    end
  end

  def property(
        conn,
        %{
          "property" => property,
          "access_token" => access_token,
          "refresh_token" => refresh_token,
          "expires_at" => expires_at
        } = params
      ) do
    site = conn.assigns.site

    redirect_route = Routes.site_path(conn, :settings_imports_exports, site.domain)

    with {:ok, api_start_date} <- Google.API.get_analytics_start_date(access_token, property),
         {:ok, api_end_date} <- Google.API.get_analytics_end_date(access_token, property),
         :ok <- ensure_dates(api_start_date, api_end_date),
         {:ok, start_date, end_date} <- Imported.clamp_dates(site, api_start_date, api_end_date) do
      redirect(conn,
        to:
          Routes.google_analytics_path(conn, :confirm, site.domain,
            property: property,
            access_token: access_token,
            refresh_token: refresh_token,
            expires_at: expires_at,
            start_date: Date.to_iso8601(start_date),
            end_date: Date.to_iso8601(end_date)
          )
      )
    else
      {:error, error} when error in [:no_data, :no_time_window] ->
        params =
          params
          |> Map.take(["access_token", "refresh_token", "expires_at"])
          |> Map.put("error", Atom.to_string(error))

        property_form(conn, params)

      {:error, :rate_limit_exceeded} ->
        conn
        |> put_flash(
          :error,
          "Google Analytics rate limit has been exceeded. Please try again later."
        )
        |> redirect(to: redirect_route)

      {:error, {:authentication_failed, message}} ->
        default_message =
          "Google Analytics authentication seems to have expired. Please try again."

        message =
          if ce?() do
            message || default_message
          else
            default_message
          end

        conn
        |> put_flash(:ttl, :timer.seconds(5))
        |> put_flash(:error, message)
        |> redirect(to: redirect_route)

      {:error, :timeout} ->
        conn
        |> put_flash(
          :error,
          "Google Analytics API has timed out. Please try again."
        )
        |> redirect(to: redirect_route)

      {:error, _any} ->
        conn
        |> put_flash(
          :error,
          "We were unable to retrieve information from Google Analytics. If the problem persists, please contact support for assistance."
        )
        |> redirect(to: redirect_route)
    end
  end

  def confirm(conn, %{
        "property" => property,
        "access_token" => access_token,
        "refresh_token" => refresh_token,
        "expires_at" => expires_at,
        "start_date" => start_date,
        "end_date" => end_date
      }) do
    site = conn.assigns.site

    start_date = Date.from_iso8601!(start_date)
    end_date = Date.from_iso8601!(end_date)

    redirect_route = Routes.site_path(conn, :settings_imports_exports, site.domain)

    case Google.API.get_property(access_token, property) do
      {:ok, %{name: property_name, id: property}} ->
        conn
        |> assign(:skip_plausible_tracking, true)
        |> render("confirm.html",
          access_token: access_token,
          refresh_token: refresh_token,
          expires_at: expires_at,
          site: site,
          selected_property: property,
          selected_property_name: property_name,
          start_date: start_date,
          end_date: end_date
        )

      {:error, :rate_limit_exceeded} ->
        conn
        |> put_flash(
          :error,
          "Google Analytics rate limit has been exceeded. Please try again later."
        )
        |> redirect(to: redirect_route)

      {:error, {:authentication_failed, message}} ->
        default_message =
          "Google Analytics authentication seems to have expired. Please try again."

        message =
          if ce?() do
            message || default_message
          else
            default_message
          end

        conn
        |> put_flash(:ttl, :timer.seconds(5))
        |> put_flash(:error, message)
        |> redirect(to: redirect_route)

      {:error, :timeout} ->
        conn
        |> put_flash(
          :error,
          "Google Analytics API has timed out. Please try again."
        )
        |> redirect(to: redirect_route)

      {:error, :not_found} ->
        conn
        |> put_flash(
          :error,
          "Google Analytics property not found. Please try again."
        )
        |> redirect(to: redirect_route)

      {:error, _any} ->
        conn
        |> put_flash(
          :error,
          "We were unable to retrieve information from Google Analytics. If the problem persists, please contact support for assistance."
        )
        |> redirect(to: redirect_route)
    end
  end

  def import(conn, %{
        "property" => property,
        "start_date" => start_date,
        "end_date" => end_date,
        "access_token" => access_token,
        "refresh_token" => refresh_token,
        "expires_at" => expires_at
      }) do
    site = conn.assigns.site
    current_user = conn.assigns.current_user

    start_date = Date.from_iso8601!(start_date)
    end_date = Date.from_iso8601!(end_date)

    redirect_route = Routes.site_path(conn, :settings_imports_exports, site.domain)

    import_opts = [
      label: property,
      property: property,
      start_date: start_date,
      end_date: end_date,
      access_token: access_token,
      refresh_token: refresh_token,
      token_expires_at: expires_at
    ]

    with {:ok, start_date, end_date} <- Imported.clamp_dates(site, start_date, end_date),
         import_opts = [{:start_date, start_date}, {:end_date, end_date} | import_opts],
         {:ok, _} <- Imported.GoogleAnalytics4.new_import(site, current_user, import_opts) do
      conn
      |> put_flash(:success, "Import scheduled. An email will be sent when it completes.")
      |> redirect(to: redirect_route)
    else
      {:error, :no_time_window} ->
        conn
        |> put_flash(
          :error,
          "Import failed. No data could be imported because date range overlaps with existing data."
        )
        |> redirect(to: redirect_route)

      {:error, :import_in_progress} ->
        conn
        |> put_flash(
          :error,
          "There's another import still in progress. Please wait until it's completed or cancel it before starting a new one."
        )
        |> redirect(to: redirect_route)
    end
  end

  defp ensure_dates(%Date{}, %Date{}), do: :ok
  defp ensure_dates(_, _), do: {:error, :no_data}
end
