import type { CatalogStoryGroup } from "@/lib/catalog-stories";

/*
  Fotos no tamanho da tela, não no tamanho do arquivo.

  O lojista sobe a foto como saiu do celular (a média do bucket é 1,2 MB, e
  há originais de 40 MB). A vitrine mostrava esse arquivo inteiro num quadrado
  de 200 px. Aqui a URL pública do Storage vira a URL do serviço de imagem do
  Supabase, que encolhe, converte para WebP e guarda na CDN: a mesma foto de
  2 MB desce com 30 KB.

  Só URLs do próprio Storage são trocadas. Foto de fornecedor (XBZ), data URL
  ou qualquer outro endereço passa intacto. O serviço recusa originais acima
  de 25 MB; para esses o navegador volta ao arquivo original sozinho (ver o
  script no layout raiz), e a foto aparece do mesmo jeito, só que pesada.
*/

const MARCA_PUBLICA = "/storage/v1/object/public/";
const MARCA_RENDER = "/storage/v1/render/image/public/";

/* Tamanhos usados pela vitrine, em px de largura. Cada um cobre tela retina
   no lugar onde é usado (card de 300 px pede 600). */
export const TAMANHO = {
  card: 640,
  produto: 1200,
  banner: 1600,
  logo: 480,
  storyCapa: 240,
  story: 1080,
  miniatura: 320,
} as const;

export function miniatura<T extends string | null | undefined>(url: T, largura: number, qualidade = 75): T {
  const texto = String(url ?? "").trim();
  if (!texto) return url;
  if (!/^https:\/\/[a-z0-9-]+\.supabase\.(co|in)\//i.test(texto)) return url;
  if (texto.includes(MARCA_RENDER)) return url;
  const inicio = texto.indexOf(MARCA_PUBLICA);
  if (inicio < 0) return url;
  const [semBusca] = texto.split("?");
  const caminho = semBusca.slice(inicio + MARCA_PUBLICA.length);
  /* SVG e GIF o serviço não trata bem (vetor perde, animação para). */
  if (!caminho || /\.(svg|gif)$/i.test(caminho)) return url;
  const base = semBusca.slice(0, inicio);
  const w = Math.max(16, Math.min(2500, Math.round(largura)));
  const q = Math.max(20, Math.min(100, Math.round(qualidade)));
  return `${base}${MARCA_RENDER}${caminho}?width=${w}&quality=${q}&resize=contain` as T;
}

type ComFoto = {
  image_url?: string | null;
  product_images?: unknown;
};

/* Um produto com a foto principal e a galeria no tamanho pedido. Mantém o
   resto do objeto como veio, inclusive o tipo. */
export function produtoComFotoMenor<T extends ComFoto>(produto: T, largura: number): T {
  if (!produto || typeof produto !== "object") return produto;
  const galeria = Array.isArray(produto.product_images)
    ? produto.product_images.map((img) =>
        img && typeof img === "object" && "image_url" in (img as Record<string, unknown>)
          ? { ...(img as Record<string, unknown>), image_url: miniatura((img as { image_url?: string | null }).image_url, largura) }
          : img
      )
    : produto.product_images;
  return { ...produto, image_url: miniatura(produto.image_url, largura), product_images: galeria };
}

export function produtosComFotoMenor<T extends ComFoto>(produtos: T[] | null | undefined, largura: number): T[] {
  return (produtos || []).map((p) => produtoComFotoMenor(p, largura));
}

/* Stories: a capa redonda é pequena, o story ocupa a tela do celular, e o
   produto que ele aponta aparece como miniatura. */
export function storiesComFotoMenor(grupos: CatalogStoryGroup[]): CatalogStoryGroup[] {
  return grupos.map((grupo) => ({
    ...grupo,
    thumbnail_url: miniatura(grupo.thumbnail_url, TAMANHO.storyCapa),
    items: grupo.items.map((item) => ({
      ...item,
      image_url: miniatura(item.image_url, TAMANHO.story),
      product: item.product ? { ...item.product, image_url: miniatura(item.product.image_url, TAMANHO.miniatura) } : item.product,
    })),
  }));
}
