import { rotaDeQuemEsta } from "@/lib/live/servidor/rota";
import { pedirAoPainel } from "@/lib/live/servidor/interno";
import { ErroDaLive, publicarEstado } from "@/lib/live/servidor/sala";

export const runtime = "nodejs";

const TAMANHO_MAXIMO_DA_PARTE = 9.5 * 1024 * 1024;

/*
 * A gravação sai do navegador de quem apresenta, em partes de 8 MiB, e o
 * painel guarda no depósito (só ele tem a chave que escreve).
 *   ?acao=abrir   { tipo }           começa um arquivo novo
 *   ?acao=parte&n=3  (corpo binário)  uma parte
 *   ?acao=fechar  { segundos }       junta as partes: vira um arquivo da loja
 *   ?acao=cancelar                   desiste do arquivo aberto
 */
export async function POST(req: Request, { params }: { params: Promise<{ salaId: string }> }) {
  const { salaId } = await params;
  return rotaDeQuemEsta(req, salaId, async ({ admin, sala, eu }) => {
    if (eu.papel !== "apresentador") throw new ErroDaLive("Só quem apresenta grava a live.", 403);
    const url = new URL(req.url);
    const acao = url.searchParams.get("acao") || "";
    if (!["abrir", "parte", "fechar", "cancelar"].includes(acao)) throw new ErroDaLive("Ação desconhecida.", 400);
    /* Como no Meet: quem apresenta pode começar a gravar na hora, mesmo sem ter marcado antes. Fechar ou cancelar o que já está aberto sempre pode. */
    if (!sala.gravar && acao === "abrir") {
      await admin.from("live_salas").update({ gravar: true, atualizado_em: new Date().toISOString() }).eq("id", sala.id);
    }

    const consulta: Record<string, string> = { sala: sala.id, acao };
    /* De qual gravação é o pedido: um gravador velho (outra aba, ou o que recomeçou) não mexe na de agora. */
    const daGravacao = url.searchParams.get("g") || "";
    if (/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(daGravacao)) consulta.g = daGravacao;
    let corpo: ArrayBuffer | Record<string, unknown> | null = null;
    if (acao === "parte") {
      const n = Number(url.searchParams.get("n"));
      if (!Number.isInteger(n) || n < 1 || n > 10000) throw new ErroDaLive("Parte inválida.", 400);
      consulta.n = String(n);
      corpo = await req.arrayBuffer();
      if (!corpo.byteLength || corpo.byteLength > TAMANHO_MAXIMO_DA_PARTE) throw new ErroDaLive("Parte grande demais.", 413);
    } else {
      corpo = ((await req.json().catch(() => null)) as Record<string, unknown> | null) ?? {};

    }

    const resposta = await pedirAoPainel("/api/live/gravacao", consulta, corpo).catch((erro) => {
      console.error("[live] gravação: painel fora do ar", erro instanceof Error ? erro.message : erro);
      return { status: 503, json: null };
    });
    /* Redirecionamento é endereço errado (o painel mandou para o login): também é falha. */
    if (resposta.status >= 300) {
      const motivo = typeof resposta.json?.motivo === "string" ? { motivo: resposta.json.motivo } : undefined;
      throw new ErroDaLive(
        String(resposta.json?.error || "A gravação engasgou. Ela continua aqui e tentamos de novo."),
        resposta.status >= 500 || resposta.status < 400 ? 503 : resposta.status,
        motivo,
      );
    }
    /* Parou de propósito (e fechou): não recomeça sozinha se quem organiza recarregar a página. */
    if (acao === "fechar" && corpo && !(corpo instanceof ArrayBuffer) && corpo.deVez === true) {
      await admin.from("live_salas").update({ gravar: false, atualizado_em: new Date().toISOString() }).eq("id", sala.id);
    }
    if (acao === "abrir" || acao === "fechar" || acao === "cancelar") await publicarEstado(admin, sala.id);
    return resposta.json ?? { ok: true };
  });
}
