/**
 * GET /api/v1/conversations/[id]/aviso-de-mensagem — "devo avisar ESTA pessoa
 * da mensagem que acabou de chegar nesta conversa?" → `{ avisar, conteudo, canal }`.
 *
 * `conteudo` é o que a bandeja do sistema pode mostrar (a opção da empresa em
 * `settings.notificacoes`, a mesma que o funil do push aplica), decidido aqui
 * no servidor e não no navegador.
 *
 * `canal` é a REDE da conversa, traduzida por `channelBrand`, para o toast se
 * identificar sem a pessoa ler (#4094). Vem aqui, e não de um segundo pedido à
 * rota da conversa, porque esta leitura já existe: cada aviso continua custando
 * uma pergunta só (é o que `tests/unit/aviso-nao-dispara-na-importacao.test.ts`
 * conta).
 *
 * Quem lê é `hooks/notifications/useInboundMessageAlerts.ts` (toast e
 * notificação do navegador). A regra é a do push do servidor, na MESMA função:
 * `lib/notifications/destinatarios-da-mensagem.ts` — com responsável, só ele e
 * os administradores; sem responsável, ninguém enquanto a IA conduz, quem está
 * de plantão na distribuição automática, ou todos no modo manual.
 *
 * ═══ Por que uma rota nova, e não `GET /conversations/[id]` ═══
 *
 * A rota da conversa já devolve `assigned_to_user_id`, e isso basta quando a
 * conversa tem atendente. Não basta no outro ramo da regra — conversa sem
 * atendente cujo contato tem negócio aberto com dono: o dono vive em
 * `crm_leads`, e a policy de leitura dali (`fn_can_view_lead`) esconde de um
 * `agent`, no modo de visibilidade PADRÃO (`own_and_unassigned`), todo negócio
 * de outro dono. Para esse atendente, "não vejo negócio" seria indistinguível
 * de "não há negócio", e ele seria avisado justamente do cliente que é de outra
 * pessoa. A pergunta precisa ser feita onde o dono é visível — aqui, com o
 * service role — e a resposta volta como um booleano, sem expor o dono nem o
 * negócio que a pessoa não pode abrir.
 *
 * ═══ Por que o admin client, e com que cerca ═══
 *
 * A EXISTÊNCIA da conversa é conferida com o client da SESSÃO: quem não enxerga
 * a conversa recebe 404 e não aprende nada sobre ela. Só depois os fatos da
 * atribuição são lidos com o service role, e cada consulta filtra
 * `organization_id` da organização ATIVA da sessão — nunca de input.
 *
 * Read-only ⇒ sem audit (mesma regra das rotas irmãs de leitura).
 */
import { randomUUID } from "node:crypto";
import { type NextRequest } from "next/server";
import { z } from "zod";

import { fail, ok } from "@/lib/api/wrappers";
import { requireRole } from "@/lib/auth/require-role";
import { channelBrand } from "@/lib/channels/presentation";
import { traduzir } from "@/lib/i18n/dicionario";
import { logger } from "@/lib/logger";
import {
  carregarDestinatariosDaMensagem,
  usuarioRecebeAviso,
} from "@/lib/notifications/destinatarios-da-mensagem";
import { lerTelaBloqueada } from "@/lib/notifications/tela-bloqueada";
import { createAdminClient } from "@/lib/supabase/admin";
import { createClient } from "@/lib/supabase/server";

export const dynamic = "force-dynamic";

interface RouteParams {
  params: Promise<{ id: string }>;
}

export async function GET(_req: NextRequest, { params }: RouteParams): Promise<Response> {
  const requestId = randomUUID();
  // viewer+: todo membro recebe o realtime de mensagens, então todo membro
  // precisa poder perguntar se deve ser avisado.
  const authz = await requireRole("viewer", { requestId, resource: "conversations" });
  if (!authz.ok) return authz.response;
  const t = (texto: string) => traduzir(texto, authz.user.idioma);
  const { org, user } = authz;
  const { id } = await params;
  if (!z.uuid().safeParse(id).success) {
    return fail("not_found", t("Conversa não encontrada."), 404, { requestId });
  }

  const supabase = await createClient();
  const { data: conversa } = await supabase
    .from("conversations")
    .select("id, channel_sessions:channel_session_id (provider, social_platform:metadata->>social_platform)")
    .eq("id", id)
    .eq("organization_id", org.orgId)
    .maybeSingle();
  if (!conversa) return fail("not_found", t("Conversa não encontrada."), 404, { requestId });

  try {
    const destino = await carregarDestinatariosDaMensagem(createAdminClient(), org.orgId, id);
    // `null` só se a conversa sumiu entre as duas leituras: sem dono conhecido,
    // é fila — avisa, como antes da regra.
    const avisar = destino === null ? true : usuarioRecebeAviso(destino, user.id);
    // O que a bandeja do sistema pode mostrar é decidido aqui, no servidor,
    // pela mesma opção que o funil do push aplica.
    const { modo } = await lerTelaBloqueada(createAdminClient(), org.orgId);
    // O tipo vê o embed como lista; pela FK ele chega como objeto único.
    const sessao = conversa.channel_sessions;
    const canal = channelBrand(Array.isArray(sessao) ? sessao[0] : sessao);
    return ok({ avisar, conteudo: modo, canal }, { requestId });
  } catch (err) {
    logger.error("[aviso-de-mensagem] leitura falhou", {
      conversation_id: id,
      organization_id: org.orgId,
      error: err instanceof Error ? err.message : String(err),
      requestId,
    });
    return fail("internal_error", t("Não foi possível decidir o aviso da mensagem."), 500, { requestId });
  }
}
