defmodule ToweropsWeb.GraphQL.Resolvers.EscalationPolicy do @moduledoc "GraphQL resolvers for escalation policy queries and mutations." alias Towerops.OnCall alias Towerops.OnCall.EscalationPolicy alias Towerops.OnCall.EscalationRule alias Towerops.OnCall.EscalationTarget alias Towerops.Repo alias ToweropsWeb.GraphQL.Resolvers.Helpers alias ToweropsWeb.ScopedResource # --- Queries --- def list(_parent, _args, %{context: %{organization_id: org_id}}) do {:ok, OnCall.list_escalation_policies(org_id)} end def list(_parent, _args, _resolution), do: Helpers.authentication_error() def get(_parent, %{id: id}, %{context: %{organization_id: org_id}}) do case ScopedResource.fetch_preload(EscalationPolicy, id, org_id, rules: :targets) do {:ok, policy} -> {:ok, policy} {:error, _} -> {:error, "Escalation policy not found"} end end def get(_parent, _args, _resolution), do: Helpers.authentication_error() # --- Mutations --- def create(_parent, %{input: input}, %{context: %{organization_id: org_id}}) do attrs = input |> Map.new(fn {k, v} -> {to_string(k), v} end) |> Map.put("organization_id", org_id) case OnCall.create_escalation_policy(attrs) do {:ok, policy} -> {:ok, policy} {:error, changeset} -> {:error, Helpers.format_changeset_errors(changeset)} end end def create(_parent, _args, _resolution), do: Helpers.authentication_error() def update(_parent, %{id: id, input: input}, %{context: %{organization_id: org_id}}) do with {:ok, policy} <- fetch_org_policy(id, org_id) do attrs = Map.new(input, fn {k, v} -> {to_string(k), v} end) case OnCall.update_escalation_policy(policy, attrs) do {:ok, updated} -> {:ok, updated} {:error, changeset} -> {:error, Helpers.format_changeset_errors(changeset)} end end end def update(_parent, _args, _resolution), do: Helpers.authentication_error() def delete(_parent, %{id: id}, %{context: %{organization_id: org_id}}) do with {:ok, policy} <- fetch_org_policy(id, org_id) do case OnCall.delete_escalation_policy(policy) do {:ok, _} -> {:ok, %{success: true, message: "Escalation policy deleted"}} {:error, _} -> {:ok, %{success: false, message: "Could not delete escalation policy"}} end end end def delete(_parent, _args, _resolution), do: Helpers.authentication_error() # --- Rule mutations --- def create_rule(_parent, %{escalation_policy_id: policy_id, input: input}, %{context: %{organization_id: org_id}}) do with {:ok, _policy} <- fetch_org_policy(policy_id, org_id) do attrs = input |> Map.new(fn {k, v} -> {to_string(k), v} end) |> Map.put("escalation_policy_id", policy_id) case OnCall.create_escalation_rule(attrs) do {:ok, rule} -> {:ok, rule} {:error, changeset} -> {:error, Helpers.format_changeset_errors(changeset)} end end end def create_rule(_parent, _args, _resolution), do: Helpers.authentication_error() def update_rule(_parent, %{id: id, input: input}, %{context: %{organization_id: org_id}}) do with {:ok, rule} <- fetch_rule_by_org(id, org_id) do attrs = Map.new(input, fn {k, v} -> {to_string(k), v} end) case OnCall.update_escalation_rule(rule, attrs) do {:ok, updated} -> {:ok, updated} {:error, changeset} -> {:error, Helpers.format_changeset_errors(changeset)} end end end def update_rule(_parent, _args, _resolution), do: Helpers.authentication_error() def delete_rule(_parent, %{id: id}, %{context: %{organization_id: org_id}}) do with {:ok, rule} <- fetch_rule_by_org(id, org_id) do case OnCall.delete_escalation_rule(rule) do {:ok, _} -> {:ok, %{success: true, message: "Rule deleted"}} {:error, _} -> {:ok, %{success: false, message: "Could not delete rule"}} end end end def delete_rule(_parent, _args, _resolution), do: Helpers.authentication_error() # --- Target mutations --- def create_target(_parent, %{escalation_rule_id: rule_id, input: input}, %{context: %{organization_id: org_id}}) do with {:ok, _rule} <- fetch_rule_by_org(rule_id, org_id) do attrs = input |> Map.new(fn {k, v} -> {to_string(k), v} end) |> Map.put("escalation_rule_id", rule_id) case OnCall.create_escalation_target(attrs) do {:ok, target} -> {:ok, target} {:error, changeset} -> {:error, Helpers.format_changeset_errors(changeset)} end end end def create_target(_parent, _args, _resolution), do: Helpers.authentication_error() def delete_target(_parent, %{id: id}, %{context: %{organization_id: _org_id}}) do case Repo.get(EscalationTarget, id) do nil -> {:error, "Target not found"} target -> case OnCall.delete_escalation_target(target) do {:ok, _} -> {:ok, %{success: true, message: "Target deleted"}} {:error, _} -> {:ok, %{success: false, message: "Could not delete target"}} end end end def delete_target(_parent, _args, _resolution), do: Helpers.authentication_error() # --- Private helpers --- defp fetch_org_policy(id, org_id) do case ScopedResource.fetch(EscalationPolicy, id, org_id) do {:ok, policy} -> {:ok, policy} {:error, _} -> {:error, "Escalation policy not found"} end end defp fetch_rule_by_org(rule_id, org_id) do case Repo.get(EscalationRule, rule_id) do nil -> {:error, "Rule not found"} rule -> rule = Repo.preload(rule, :escalation_policy) if rule.escalation_policy.organization_id == org_id do {:ok, rule} else {:error, "Rule not found"} end end end end