"use client";

import { createContext, useContext, type ReactNode } from "react";
import { miniatura, TAMANHO } from "@/lib/foto";
import { useNavegacaoDaLoja } from "@/components/navegacao/ContextoDaNavegacao";

/*
  O topo da loja no editor (migration 221): o banner principal, a tarja de
  vantagens, o aviso do topo e os stories.

  O painel manda o rascunho do topo (mensagem "topo"); o NavegacaoNoEditor
  guarda e põe neste contexto. Cada template pergunta aqui antes de usar o
  que veio do banco: sem rascunho (fora do editor, ou antes da primeira
  mensagem) o valor é null e a loja desenha como sempre.

  Arquivo leve de propósito: os shells e as homes de todo dia importam dele.
*/

export type ParteDoTopo = "banner" | "tarja" | "aviso" | "stories";

export type SlideDoRascunho = {
  image_url: string;
  link_type: "none" | "product" | "url";
  product_id: string | null;
  link_url: string | null;
  open_in_new_tab: boolean;
  active: boolean;
};

export type CupomDoRascunho = {
  id: string;
  code: string;
  type: "percent" | "value" | "free_shipping";
  value: number;
  active: boolean;
  starts_at?: string | null;
  ends_at?: string | null;
};

export type AvisoDoRascunho = {
  enabled: boolean;
  text: string | null;
  countdown_enabled: boolean;
  countdown_end_at: string | null;
  coupon_id: string | null;
  show_coupon_badge: boolean;
  coupon_badge_color: string | null;
  background_color: string | null;
  text_color: string | null;
  button_label: string | null;
  button_url: string | null;
  sticky: boolean;
};

export type TopoDoRascunho = {
  slides: SlideDoRascunho[];
  slide_ligado: boolean;
  stories_ligados: boolean;
  tarja: { ligada: boolean; itens: Array<{ icon: string; title: string; subtitle: string }> };
  aviso: AvisoDoRascunho;
  /* O cupom escolhido no aviso, já lido pelo painel (a loja não vai ao banco). */
  cupom: CupomDoRascunho | null;
};

const ContextoDoTopo = createContext<TopoDoRascunho | null>(null);

export function ProvedorDoTopo({ topo, children }: { topo: TopoDoRascunho | null; children: ReactNode }) {
  return <ContextoDoTopo.Provider value={topo}>{children}</ContextoDoTopo.Provider>;
}

/** O rascunho do topo que o painel mandou; null = vale o que veio do banco. */
export function useTopoDoRascunho() {
  return useContext(ContextoDoTopo);
}

/* ------------------------------------------------------ ler a mensagem */

function objeto(valor: unknown): Record<string, unknown> | null {
  return valor && typeof valor === "object" && !Array.isArray(valor) ? (valor as Record<string, unknown>) : null;
}

function textoOuNulo(valor: unknown, limite: number) {
  const t = typeof valor === "string" ? valor.slice(0, limite) : "";
  return t.trim() ? t : null;
}

function cor(valor: unknown) {
  return typeof valor === "string" && /^#[0-9a-f]{6}$/i.test(valor) ? valor : null;
}

function enderecoDaImagem(valor: unknown) {
  const t = typeof valor === "string" ? valor.trim() : "";
  return /^(https?:\/\/|\/)/i.test(t) ? t.slice(0, 2000) : "";
}

/** Confere o que veio do painel: nada de fora do formato chega aos templates. */
export function lerTopoDoRascunho(dados: unknown): TopoDoRascunho | null {
  const m = objeto(dados);
  if (!m) return null;
  const slides = (Array.isArray(m.slides) ? m.slides : [])
    .slice(0, 12)
    .map((bruto) => {
      const s = objeto(bruto) || {};
      const tipo = s.link_type === "product" || s.link_type === "url" ? s.link_type : "none";
      return {
        image_url: enderecoDaImagem(s.image_url),
        link_type: tipo,
        product_id: tipo === "product" && typeof s.product_id === "string" ? s.product_id : null,
        link_url: tipo === "url" ? textoOuNulo(s.link_url, 2000) : null,
        open_in_new_tab: s.open_in_new_tab === true,
        active: s.active !== false,
      } satisfies SlideDoRascunho;
    })
    .filter((s) => s.image_url);
  const tarja = objeto(m.tarja) || {};
  const aviso = objeto(m.aviso) || {};
  const cupom = objeto(m.cupom);
  return {
    slides,
    slide_ligado: m.slide_ligado === true,
    stories_ligados: m.stories_ligados !== false,
    tarja: {
      ligada: tarja.ligada !== false,
      itens: (Array.isArray(tarja.itens) ? tarja.itens : []).slice(0, 6).map((bruto) => {
        const i = objeto(bruto) || {};
        return {
          icon: typeof i.icon === "string" ? i.icon.slice(0, 40) : "truck",
          title: typeof i.title === "string" ? i.title.slice(0, 80) : "",
          subtitle: typeof i.subtitle === "string" ? i.subtitle.slice(0, 120) : "",
        };
      }),
    },
    aviso: {
      enabled: aviso.enabled === true,
      text: textoOuNulo(aviso.text, 240),
      countdown_enabled: aviso.countdown_enabled === true,
      countdown_end_at: textoOuNulo(aviso.countdown_end_at, 40),
      coupon_id: textoOuNulo(aviso.coupon_id, 40),
      show_coupon_badge: aviso.show_coupon_badge !== false,
      coupon_badge_color: cor(aviso.coupon_badge_color),
      background_color: cor(aviso.background_color),
      text_color: cor(aviso.text_color),
      button_label: textoOuNulo(aviso.button_label, 40),
      button_url: textoOuNulo(aviso.button_url, 2000),
      sticky: aviso.sticky !== false,
    },
    cupom:
      cupom && typeof cupom.id === "string" && typeof cupom.code === "string"
        ? {
            id: cupom.id,
            code: cupom.code.slice(0, 40),
            type: cupom.type === "percent" || cupom.type === "free_shipping" ? cupom.type : "value",
            value: Number(cupom.value) || 0,
            active: cupom.active !== false,
            starts_at: textoOuNulo(cupom.starts_at, 40),
            ends_at: textoOuNulo(cupom.ends_at, 40),
          }
        : null,
  };
}

/* ------------------------------------------- o rascunho nos templates */

/** Os slides do rascunho no formato dos banners que os templates já usam. */
export function bannersDoRascunho(topo: TopoDoRascunho) {
  if (!topo.slide_ligado) return [];
  return topo.slides
    .filter((s) => s.active)
    .map((s, posicao) => ({
      id: `rascunho-${posicao}`,
      image_url: miniatura(s.image_url, TAMANHO.banner),
      link_type: s.link_type,
      product_id: s.product_id ?? undefined,
      link_url: s.link_url ?? undefined,
      open_in_new_tab: s.open_in_new_tab,
      position: posicao,
    }));
}

/** O cupom do aviso: o do rascunho quando ele escolheu um, senão nenhum. */
export function cupomDoAvisoDoRascunho(topo: TopoDoRascunho) {
  return topo.aviso.coupon_id && topo.cupom?.id === topo.aviso.coupon_id ? topo.cupom : null;
}

/**
 * Marca uma parte do topo como clicável no editor. A caixa some do desenho
 * (display: contents): o contorno vai no filho, e fora do editor nem existe.
 */
export function MarcaDoTopo({ parte, children }: { parte: ParteDoTopo; children: ReactNode }) {
  const { noEditor } = useNavegacaoDaLoja();
  if (!noEditor) return <>{children}</>;
  return (
    <div data-ks-topo={parte} style={{ display: "contents" }}>
      {children}
    </div>
  );
}

/**
 * O aviso do rascunho nos campos de aparência do Vendor e do Ateliê (os dois
 * usam os mesmos nomes). Sem rascunho, devolve a aparência como veio.
 */
export function comAvisoDoRascunho<T extends object>(aparencia: T, topo: TopoDoRascunho | null): T {
  if (!topo) return aparencia;
  const a = topo.aviso;
  return {
    ...aparencia,
    avisoLigado: a.enabled,
    avisoTexto: a.text,
    avisoCorDeFundo: a.background_color,
    avisoCorDoTexto: a.text_color,
    avisoBotaoRotulo: a.button_label,
    avisoBotaoUrl: a.button_url,
    avisoMostrarSelo: a.show_coupon_badge,
    avisoCorDoSelo: a.coupon_badge_color,
    avisoContagemLigada: a.countdown_enabled,
    avisoContagemAte: a.countdown_end_at,
    avisoFixo: a.sticky,
  } as T;
}
