import { cookies } from "next/headers";

import type { SupabaseClient } from "@supabase/supabase-js";

import { COOKIE_DA_SESSAO } from "@/lib/loja/visao.server";

import { linkGuardado, quandoAbre, rotuloDeQuandoAbre, type LinkDeVideo, type TipoDeAula } from "../curso";
import { dataCurtaDeBrasilia, lerConfigDigitalDaLoja } from "../produto";
import { aulaParaContinuar } from "../progresso-do-curso";
import { conferirChave } from "./acessos";

/*
 * O curso do lado do aluno.
 *
 * Quem assiste prova o acesso por um destes caminhos, e cada um só abre o que
 * é dele:
 * - a sessão do portal da loja (área de membros): os cursos daquele cliente;
 * - a chave da compra (cookie do navegador que comprou): os cursos daquele pedido;
 * - a chave do link do e-mail, trocada por um cookie no clique "Assistir": idem;
 * - a prévia da equipe ("Ver como aluno", link de 2 horas do painel): todos os
 *   cursos da loja, só para olhar (não grava progresso nem comenta).
 *
 * O servidor confere tudo a cada pedido: a tela nunca decide sozinha o que abre.
 */

export const COOKIE_DA_PREVIA = "ks_previa";

/* O cookie do link do e-mail: um por pedido, só HTTP. */
export function nomeDoCookieDaEntrega(orderId: string): string {
  return `ks_entrega_${orderId.replace(/[^0-9a-f]/gi, "").slice(0, 32)}`;
}

export type Espectador =
  | { tipo: "aluno"; clienteId: string; inicio: string | null; expiraEm: string | null }
  | { tipo: "equipe" }
  | { tipo: "fechado"; motivo: string }
  | null;

type AcessoDoCurso = {
  client_id: string;
  status: string;
  motivo: string | null;
  liberado_em: string | null;
  libera_em: string | null;
  expira_em: string | null;
  order_id: string | null;
};

/* O acesso ao curso que vale (ativo e no prazo), entre os encontrados. */
function melhorAcesso(linhas: AcessoDoCurso[], tipo: "curso" | "live" = "curso"): Espectador {
  if (!linhas.length) return null;
  const agora = Date.now();
  const valendo = linhas.find((l) => l.status === "ativo" && !(l.expira_em && new Date(l.expira_em).getTime() < agora));
  if (valendo) return { tipo: "aluno", clienteId: valendo.client_id, inicio: valendo.liberado_em, expiraEm: valendo.expira_em };
  const primeiro = linhas[0];
  if (primeiro.status === "ativo" || primeiro.status === "expirado") return { tipo: "fechado", motivo: `O prazo do seu acesso ${tipo === "live" ? "a esta live" : "a este conteúdo"} terminou. Fale com a loja.` };
  if (primeiro.status === "suspenso") return { tipo: "fechado", motivo: "Acesso suspenso: o pagamento não foi confirmado ou foi devolvido." };
  if (primeiro.status === "revogado") return { tipo: "fechado", motivo: "Este pedido foi cancelado." };
  /* Pré-venda: o curso abre sozinho na data. */
  const agendado = linhas.find((l) => l.status === "agendado");
  if (agendado) {
    return {
      tipo: "fechado",
      motivo: agendado.libera_em
        ? `Pré-venda: o conteúdo abre em ${dataCurtaDeBrasilia(agendado.libera_em)}. Nesse dia você recebe um e-mail e já pode assistir.`
        : "Pré-venda: o conteúdo abre na data do lançamento. Você recebe um e-mail nesse dia.",
    };
  }
  /* O freio de compartilhamento pausou: a loja reativa. */
  if (primeiro.status === "pausado" && (primeiro.motivo ?? "").startsWith("freio")) {
    return { tipo: "fechado", motivo: "Acesso pausado: ele foi aberto em muitos lugares diferentes. Fale com a loja para reativar." };
  }
  return { tipo: "fechado", motivo: "Acesso pausado pela loja. Fale com ela." };
}

async function acessosDoCurso(
  admin: SupabaseClient,
  lojaId: string,
  produtoId: string,
  filtro: { clienteId?: string; pedidos?: string[] },
  tipo: "curso" | "live" = "curso"
) {
  let consulta = admin
    .from("digital_entitlements")
    .select("client_id,status,motivo,liberado_em,libera_em,expira_em,order_id,digital_deliverables!inner(tipo)")
    .eq("user_id", lojaId)
    .eq("product_id", produtoId)
    .eq("digital_deliverables.tipo", tipo);
  if (filtro.clienteId) consulta = consulta.eq("client_id", filtro.clienteId);
  if (filtro.pedidos) consulta = consulta.in("order_id", filtro.pedidos);
  const { data } = await consulta.order("liberado_em", { ascending: true }).limit(20);
  return (data ?? []) as unknown as AcessoDoCurso[];
}

/** O cliente do portal logado nesta loja (área de membros), ou null. */
export async function clienteDaSessao(admin: SupabaseClient, slug: string): Promise<string | null> {
  const sessao = (await cookies()).get(COOKIE_DA_SESSAO)?.value ?? "";
  if (!sessao) return null;
  const { data } = await admin.rpc("client_portal_get_session", { p_slug: slug, p_session_token: sessao });
  const id = String((data as { client?: { id?: string } } | null)?.client?.id ?? "");
  return id || null;
}

/** Quem está assistindo este curso (ou esta live: `tipo: "live"`), e se pode. */
export async function quemAssiste(
  admin: SupabaseClient,
  params: { slug: string; lojaId: string; produtoId: string; tipo?: "curso" | "live" }
): Promise<Espectador> {
  const { slug, lojaId, produtoId } = params;
  const tipo = params.tipo ?? "curso";
  const jar = await cookies();

  /* 1. A sessão do portal (área de membros). */
  const clienteId = await clienteDaSessao(admin, slug);
  let fechado: Espectador = null;
  if (clienteId) {
    const resultado = melhorAcesso(await acessosDoCurso(admin, lojaId, produtoId, { clienteId }, tipo), tipo);
    if (resultado?.tipo === "aluno") return resultado;
    fechado = resultado;
  }

  /* 2 e 3. As chaves da compra e do link do e-mail guardadas neste navegador. */
  const pedidos = new Set<string>();
  for (const cookie of jar.getAll()) {
    if (cookie.name.startsWith("ks_compra_")) {
      const conferida = await conferirChave(admin, cookie.value, "compra");
      if (conferida?.lojaId === lojaId && conferida.catalogOrderId) {
        const { data } = await admin.from("catalog_orders").select("approved_order_id").eq("id", conferida.catalogOrderId).maybeSingle();
        const pedido = (data as { approved_order_id?: string | null } | null)?.approved_order_id;
        if (pedido) pedidos.add(pedido);
      }
    } else if (cookie.name.startsWith("ks_entrega_")) {
      const conferida = await conferirChave(admin, cookie.value, "entrega");
      if (conferida?.lojaId === lojaId && conferida.orderId) pedidos.add(conferida.orderId);
    }
    if (pedidos.size >= 10) break;
  }
  if (pedidos.size) {
    const resultado = melhorAcesso(await acessosDoCurso(admin, lojaId, produtoId, { pedidos: Array.from(pedidos) }, tipo), tipo);
    if (resultado?.tipo === "aluno") return resultado;
    fechado = fechado ?? resultado;
  }

  /* 4. A prévia da equipe. */
  const previa = jar.get(COOKIE_DA_PREVIA)?.value ?? "";
  if (previa) {
    const conferida = await conferirChave(admin, previa, "entrar");
    if (conferida && conferida.lojaId === lojaId && !conferida.clienteId && !conferida.orderId) return { tipo: "equipe" };
  }
  return fechado;
}

/* ------------------------------------------------------------ estrutura */

export type AulaDoAluno = {
  id: string;
  moduloId: string;
  titulo: string;
  tipo: TipoDeAula;
  duracaoS: number | null;
  temVideoProprio: boolean;
  link: LinkDeVideo | null;
  aberta: boolean;
  abre: string | null;
  comentarios: boolean;
  materiais: number;
};

export type ModuloDoAluno = { id: string; titulo: string; descricao: string | null; capa: string | null; aberto: boolean; abre: string | null; aulas: AulaDoAluno[] };

type LinhaDoModulo = { id: string; titulo: string; descricao: string | null; capa_url: string | null; liberacao: "imediata" | "dias" | "data"; liberar_dias: number | null; liberar_em: string | null };
type LinhaDaAula = {
  id: string;
  module_id: string;
  titulo: string;
  tipo: TipoDeAula;
  video_file_id: string | null;
  video_link: unknown;
  duracao_s: number | null;
  texto: string | null;
  ao_vivo_em: string | null;
  ao_vivo_link: string | null;
  comentarios: boolean;
  liberacao: "modulo" | "dias" | "data";
  liberar_dias: number | null;
  liberar_em: string | null;
  digital_files: { status: string } | null;
  digital_course_materials: Array<{ id: string }> | null;
};

/* A aula tem o que mostrar para o aluno? */
function temConteudo(aula: LinhaDaAula): boolean {
  if (aula.tipo === "video") return Boolean((aula.video_file_id && aula.digital_files?.status === "pronto") || linkGuardado(aula.video_link));
  if (aula.tipo === "texto") return Boolean(aula.texto?.trim());
  if (aula.tipo === "materiais") return Boolean(aula.digital_course_materials?.length);
  return Boolean(aula.ao_vivo_em && aula.ao_vivo_link);
}

/**
 * Os módulos e aulas que o aluno vê, com o que já abriu para ele (`inicio` é
 * quando o acesso foi liberado; a equipe vê tudo aberto).
 */
export async function estruturaParaAluno(
  admin: SupabaseClient,
  params: { lojaId: string; produtoId: string; inicio: string | null; equipe: boolean }
): Promise<ModuloDoAluno[]> {
  const [modulos, aulas] = await Promise.all([
    admin
      .from("digital_course_modules")
      .select("id,titulo,descricao,capa_url,liberacao,liberar_dias,liberar_em")
      .eq("user_id", params.lojaId)
      .eq("product_id", params.produtoId)
      .is("apagado_em", null)
      .order("posicao", { ascending: true })
      .order("criado_em", { ascending: true }),
    admin
      .from("digital_course_lessons")
      .select(
        "id,module_id,titulo,tipo,video_file_id,video_link,duracao_s,texto,ao_vivo_em,ao_vivo_link,comentarios,liberacao,liberar_dias,liberar_em,digital_files!digital_course_lessons_video_file_id_fkey(status),digital_course_materials(id)"
      )
      .eq("user_id", params.lojaId)
      .eq("product_id", params.produtoId)
      .eq("publicada", true)
      .is("apagado_em", null)
      .order("posicao", { ascending: true })
      .order("criado_em", { ascending: true }),
  ]);
  const agora = Date.now();
  const porModulo = new Map<string, LinhaDaAula[]>();
  for (const aula of (aulas.data ?? []) as unknown as LinhaDaAula[]) {
    if (!temConteudo(aula)) continue;
    const lista = porModulo.get(aula.module_id) ?? [];
    lista.push(aula);
    porModulo.set(aula.module_id, lista);
  }
  return ((modulos.data ?? []) as LinhaDoModulo[])
    .map((m) => {
      const regraDoModulo = { liberacao: m.liberacao, dias: m.liberar_dias, em: m.liberar_em };
      const moduloAbre = params.equipe ? { aberta: true, abreEm: null } : quandoAbre({ inicio: params.inicio, modulo: regraDoModulo, agora });
      return {
        id: m.id,
        titulo: m.titulo,
        descricao: m.descricao,
        capa: m.capa_url,
        aberto: moduloAbre.aberta,
        abre: rotuloDeQuandoAbre(moduloAbre.abreEm, agora),
        aulas: (porModulo.get(m.id) ?? []).map((a) => {
          const abre = params.equipe
            ? { aberta: true, abreEm: null }
            : quandoAbre({
                inicio: params.inicio,
                modulo: regraDoModulo,
                aula: { liberacao: a.liberacao, dias: a.liberar_dias, em: a.liberar_em },
                agora,
              });
          return {
            id: a.id,
            moduloId: a.module_id,
            titulo: a.titulo,
            tipo: a.tipo,
            duracaoS: a.duracao_s,
            temVideoProprio: Boolean(a.video_file_id),
            link: linkGuardado(a.video_link),
            aberta: abre.aberta,
            abre: rotuloDeQuandoAbre(abre.abreEm, agora),
            comentarios: a.comentarios,
            materiais: a.digital_course_materials?.length ?? 0,
          };
        }),
      };
    })
    .filter((m) => m.aulas.length > 0);
}

export type ProgressoDaAula = { posicaoS: number; assistidoS: number; duracaoS: number | null; concluida: boolean; atualizadoEm: string };

export async function progressoDoAluno(admin: SupabaseClient, clienteId: string, produtoId: string): Promise<Map<string, ProgressoDaAula>> {
  const { data } = await admin
    .from("digital_course_progress")
    .select("lesson_id,posicao_s,assistido_s,duracao_s,concluida_em,atualizado_em")
    .eq("client_id", clienteId)
    .eq("product_id", produtoId)
    .limit(1000);
  return new Map(
    ((data ?? []) as Array<{ lesson_id: string; posicao_s: number; assistido_s: number; duracao_s: number | null; concluida_em: string | null; atualizado_em: string }>).map(
      (p) => [p.lesson_id, { posicaoS: p.posicao_s, assistidoS: p.assistido_s, duracaoS: p.duracao_s, concluida: Boolean(p.concluida_em), atualizadoEm: p.atualizado_em }]
    )
  );
}

/* A aula (do curso desta loja), com o produto dela. */
export async function lerAulaDaLoja(admin: SupabaseClient, lojaId: string, aulaId: string) {
  if (!/^[0-9a-f-]{36}$/i.test(aulaId)) return null;
  const { data } = await admin
    .from("digital_course_lessons")
    .select(
      "id,product_id,module_id,titulo,tipo,video_file_id,video_link,duracao_s,descricao,texto,ao_vivo_em,ao_vivo_link,comentarios,previa_gratis,publicada,atualizado_em,capitulos,digital_files!digital_course_lessons_video_file_id_fkey(storage_key,nome,mime,status),legenda:digital_files!digital_course_lessons_legenda_file_id_fkey(storage_key,nome,extensao,status),products!inner(id,name,image_url,active,show_in_catalog,product_kind)"
    )
    .eq("id", aulaId)
    .eq("user_id", lojaId)
    .is("apagado_em", null)
    .maybeSingle();
  return (data as unknown as {
    id: string;
    product_id: string;
    module_id: string;
    titulo: string;
    tipo: TipoDeAula;
    video_file_id: string | null;
    video_link: unknown;
    duracao_s: number | null;
    descricao: string | null;
    texto: string | null;
    ao_vivo_em: string | null;
    ao_vivo_link: string | null;
    comentarios: boolean;
    previa_gratis: boolean;
    publicada: boolean;
    atualizado_em: string;
    capitulos: unknown;
    digital_files: { storage_key: string; nome: string; mime: string | null; status: string } | null;
    legenda: { storage_key: string; nome: string; extensao: string; status: string } | null;
    products: { id: string; name: string; image_url: string | null; active: boolean | null; show_in_catalog: boolean | null; product_kind: string | null };
  } | null) ?? null;
}

/* O nome que aparece para os outros alunos: primeiro nome e a inicial. */
export function nomeEntreAlunos(nome: string | null | undefined): string {
  const partes = String(nome || "").trim().split(/\s+/).filter(Boolean);
  if (!partes.length) return "Cliente";
  const primeiro = partes[0].charAt(0).toUpperCase() + partes[0].slice(1).toLowerCase();
  return partes.length > 1 ? `${primeiro} ${partes[partes.length - 1].charAt(0).toUpperCase()}.` : primeiro;
}

export type AcessoAAula =
  | { ok: true; lojaId: string; aula: NonNullable<Awaited<ReturnType<typeof lerAulaDaLoja>>>; quem: { tipo: "aluno"; clienteId: string; inicio: string | null; expiraEm: string | null } | { tipo: "equipe" } }
  | { ok: false; status: number; motivo: string };

/** Quem pede pode ver esta aula agora? (loja pelo slug, curso, acesso e liberação). */
export async function acessoAAula(admin: SupabaseClient, params: { slug: string; aulaId: string }): Promise<AcessoAAula> {
  const { data: perfil } = await admin.from("profiles").select("id").eq("slug", params.slug).maybeSingle();
  const lojaId = String((perfil as { id?: string } | null)?.id || "");
  const aula = lojaId ? await lerAulaDaLoja(admin, lojaId, params.aulaId) : null;
  if (!aula || !aula.publicada) return { ok: false, status: 404, motivo: "Vídeo não encontrado." };
  const quem = await quemAssiste(admin, { slug: params.slug, lojaId, produtoId: aula.product_id });
  if (!quem) return { ok: false, status: 403, motivo: "Entre na área de membros para ver este vídeo." };
  if (quem.tipo === "fechado") return { ok: false, status: 403, motivo: quem.motivo };
  if (quem.tipo === "aluno") {
    const modulos = await estruturaParaAluno(admin, { lojaId, produtoId: aula.product_id, inicio: quem.inicio, equipe: false });
    const daAula = modulos.flatMap((m) => m.aulas).find((a) => a.id === aula.id);
    if (!daAula) return { ok: false, status: 404, motivo: "Vídeo não encontrado." };
    if (!daAula.aberta) return { ok: false, status: 403, motivo: `Este vídeo ${daAula.abre ?? "ainda não abriu"}.` };
  }
  return { ok: true, lojaId, aula, quem };
}

export type CursoDaLoja = {
  id: string;
  nome: string;
  capa: string | null;
  ativo: boolean;
  config: ReturnType<typeof lerConfigDigitalDaLoja>;
};

/* O produto do curso (desta loja). Quem comprou entra mesmo com ele fora da vitrine. */
export async function lerCursoDaLoja(admin: SupabaseClient, lojaId: string, produtoId: string): Promise<CursoDaLoja | null> {
  if (!/^[0-9a-f-]{36}$/i.test(produtoId)) return null;
  const { data } = await admin
    .from("products")
    .select("id,name,image_url,active,digital_config")
    .eq("id", produtoId)
    .eq("user_id", lojaId)
    .eq("product_kind", "digital")
    .maybeSingle();
  const linha = data as { id: string; name: string; image_url: string | null; active: boolean | null; digital_config: unknown } | null;
  if (!linha) return null;
  const config = lerConfigDigitalDaLoja(linha.digital_config);
  if (config.tipo !== "curso") return null;
  return { id: linha.id, nome: linha.name, capa: linha.image_url, ativo: linha.active !== false, config };
}

/* ------------------------------------------------------------ área de membros */

export type CursoNaArea = {
  produtoId: string;
  nome: string;
  capa: string | null;
  situacao: "liberado" | "preparando" | "fechado";
  motivo: string | null;
  total: number;
  concluidas: number;
  percentual: number;
};

export type ContinuarNaArea = {
  produtoId: string;
  curso: string;
  capa: string | null;
  aula: { id: string; titulo: string } | null;
  modo: "comecar" | "continuar" | "rever" | "em_dia";
  proximaAbre: string | null;
  percentual: number;
  /* O tamanho do curso ("18 aulas · 6h 40min"). */
  aulas: number;
  duracaoS: number;
  /* O curso dá certificado (a página junta com o das Configurações). */
  certificado: boolean;
};

/* "Continuar assistindo": as aulas de vídeo começadas e não terminadas. */
export type AssistindoNaArea = {
  produtoId: string;
  curso: string;
  capa: string | null;
  aulaId: string;
  titulo: string;
  numero: number;
  modulo: string;
  moduloNumero: number;
  restanteS: number | null;
  percentual: number;
};

/* Os módulos do curso em destaque, com o quanto já foi de cada um. */
export type ModuloNaArea = {
  id: string;
  numero: number;
  titulo: string;
  aulas: number;
  concluidas: number;
  duracaoS: number;
  aberto: boolean;
  abre: string | null;
  /* A foto do pôster (null: capa feita com a cor da área e o título). */
  capa: string | null;
  /* Para onde o quadro leva: a primeira aula aberta que falta (ou a primeira). */
  aulaId: string | null;
};

/**
 * Os cursos do aluno na área de membros, com quanto já foi de cada um, o
 * destaque "Continue de onde parou" (o curso mexido por último), as aulas
 * começadas ("Continuar assistindo") e os módulos do curso em destaque.
 */
export async function cursosDoAluno(
  admin: SupabaseClient,
  params: {
    lojaId: string;
    clienteId: string;
    acessos: Array<{ produtoId: string; produto: string; capa: string | null; tipo: string; situacao: CursoNaArea["situacao"]; motivo: string | null; liberadoEm: string | null }>;
  }
): Promise<{ cursos: CursoNaArea[]; continuar: ContinuarNaArea | null; assistindo: AssistindoNaArea[]; modulos: ModuloNaArea[] }> {
  const doCurso = params.acessos.filter((a) => a.tipo === "curso");
  const ids = Array.from(new Set(doCurso.map((a) => a.produtoId))).slice(0, 60);
  if (!ids.length) return { cursos: [], continuar: null, assistindo: [], modulos: [] };

  const [produtos, marcas] = await Promise.all([
    admin.from("products").select("id,name,image_url,digital_config").eq("user_id", params.lojaId).in("id", ids),
    admin
      .from("digital_course_progress")
      .select("product_id,lesson_id,posicao_s,duracao_s,concluida_em,atualizado_em")
      .eq("client_id", params.clienteId)
      .in("product_id", ids)
      .order("atualizado_em", { ascending: false })
      .limit(3000),
  ]);
  const porProduto = new Map(
    ((produtos.data ?? []) as Array<{ id: string; name: string; image_url: string | null; digital_config: unknown }>).map((p) => [p.id, p])
  );
  const linhas = (marcas.data ?? []) as Array<{
    product_id: string;
    lesson_id: string;
    posicao_s: number | null;
    duracao_s: number | null;
    concluida_em: string | null;
    atualizado_em: string;
  }>;

  /* O melhor acesso de cada curso (liberado vence). */
  const acessoDe = new Map<string, (typeof doCurso)[number]>();
  for (const acesso of doCurso) {
    const atual = acessoDe.get(acesso.produtoId);
    if (!atual || (atual.situacao !== "liberado" && acesso.situacao === "liberado")) acessoDe.set(acesso.produtoId, acesso);
  }

  const cursos: CursoNaArea[] = ids.map((id) => {
    const acesso = acessoDe.get(id)!;
    const produto = porProduto.get(id);
    const conteudo = produto ? lerConfigDigitalDaLoja(produto.digital_config).curso?.conteudo : null;
    const aulas = new Set((conteudo?.modulos ?? []).flatMap((m) => m.aulas.map((a) => a.id)));
    const concluidas = new Set(linhas.filter((l) => l.product_id === id && l.concluida_em && aulas.has(l.lesson_id)).map((l) => l.lesson_id)).size;
    const total = aulas.size;
    return {
      produtoId: id,
      nome: produto?.name ?? acesso.produto,
      capa: produto?.image_url ?? acesso.capa,
      situacao: acesso.situacao,
      motivo: acesso.motivo,
      total,
      concluidas,
      percentual: total ? Math.round((concluidas / total) * 100) : 0,
    };
  });

  /* "Continuar assistindo": pelo resumo do curso (sem ler as aulas de novo), a mexida por último primeiro. */
  const liberados = cursos.filter((c) => c.situacao === "liberado");
  const aulasDe = new Map<string, Map<string, { numero: number; titulo: string; tipo: TipoDeAula; duracaoS: number | null; modulo: string; moduloNumero: number }>>();
  for (const curso of liberados) {
    const produto = porProduto.get(curso.produtoId);
    const conteudo = produto ? lerConfigDigitalDaLoja(produto.digital_config).curso?.conteudo : null;
    const mapa = new Map<string, { numero: number; titulo: string; tipo: TipoDeAula; duracaoS: number | null; modulo: string; moduloNumero: number }>();
    let numero = 0;
    (conteudo?.modulos ?? []).forEach((m, i) => {
      for (const a of m.aulas) {
        numero += 1;
        mapa.set(a.id, { numero, titulo: a.titulo, tipo: a.tipo, duracaoS: a.duracaoS, modulo: m.titulo, moduloNumero: i + 1 });
      }
    });
    aulasDe.set(curso.produtoId, mapa);
  }
  const vistas = new Set<string>();
  const assistindo: AssistindoNaArea[] = [];
  for (const linha of linhas) {
    if (assistindo.length >= 10) break;
    if (linha.concluida_em || vistas.has(linha.lesson_id)) continue;
    const aula = aulasDe.get(linha.product_id)?.get(linha.lesson_id);
    const posicao = Number(linha.posicao_s) || 0;
    if (!aula || aula.tipo !== "video" || posicao < 5) continue;
    vistas.add(linha.lesson_id);
    const curso = liberados.find((c) => c.produtoId === linha.product_id)!;
    const duracao = Number(linha.duracao_s) || Number(aula.duracaoS) || 0;
    assistindo.push({
      produtoId: curso.produtoId,
      curso: curso.nome,
      capa: curso.capa,
      aulaId: linha.lesson_id,
      titulo: aula.titulo,
      numero: aula.numero,
      modulo: aula.modulo,
      moduloNumero: aula.moduloNumero,
      restanteS: duracao > posicao ? Math.round(duracao - posicao) : null,
      percentual: duracao ? Math.min(99, Math.max(1, Math.round((posicao / duracao) * 100))) : 0,
    });
  }

  /* O destaque: o curso liberado mexido por último; sem nenhum, o comprado por último. */
  if (!liberados.length) return { cursos, continuar: null, assistindo, modulos: [] };
  const mexido = linhas.find((l) => liberados.some((c) => c.produtoId === l.product_id));
  const escolhido = mexido ? liberados.find((c) => c.produtoId === mexido.product_id)! : liberados[0];
  const acesso = acessoDe.get(escolhido.produtoId)!;
  const [modulos, progresso] = await Promise.all([
    estruturaParaAluno(admin, { lojaId: params.lojaId, produtoId: escolhido.produtoId, inicio: acesso.liberadoEm, equipe: false }),
    progressoDoAluno(admin, params.clienteId, escolhido.produtoId),
  ]);
  const ordem = modulos.flatMap((m) => m.aulas);
  const alvo = aulaParaContinuar(ordem, progresso);
  const aula = alvo ? ordem.find((a) => a.id === alvo.id) ?? null : null;
  const duracaoDe = (aulas: AulaDoAluno[]) => aulas.reduce((soma, a) => soma + (a.tipo === "video" ? Number(a.duracaoS) || 0 : 0), 0);
  return {
    cursos,
    continuar: {
      produtoId: escolhido.produtoId,
      curso: escolhido.nome,
      capa: escolhido.capa,
      aula: aula ? { id: aula.id, titulo: aula.titulo } : null,
      modo: alvo?.modo ?? "em_dia",
      proximaAbre: alvo ? null : ordem.find((a) => !a.aberta)?.abre ?? null,
      percentual: escolhido.percentual,
      aulas: ordem.length,
      duracaoS: duracaoDe(ordem),
      certificado: (() => {
        const produto = porProduto.get(escolhido.produtoId);
        return produto ? lerConfigDigitalDaLoja(produto.digital_config).curso?.certificado.emitir !== false : false;
      })(),
    },
    assistindo,
    modulos: modulos.map((m, i) => {
      const abertas = m.aulas.filter((a) => a.aberta);
      const destino = abertas.find((a) => !progresso.get(a.id)?.concluida) ?? abertas[0] ?? null;
      return {
        id: m.id,
        numero: i + 1,
        titulo: m.titulo,
        aulas: m.aulas.length,
        concluidas: m.aulas.filter((a) => progresso.get(a.id)?.concluida).length,
        duracaoS: duracaoDe(m.aulas),
        aberto: abertas.length > 0,
        abre: abertas.length ? null : m.abre ?? m.aulas[0]?.abre ?? null,
        capa: m.capa,
        aulaId: destino?.id ?? null,
      };
    }),
  };
}
