import { applyMergeTags, type MergeVars } from "@/lib/blocks/merge";
import type { BlockOf } from "@/lib/blocks/schema";
import { db } from "@/lib/db";
import { cn } from "@/lib/utils";
import { messagesForSite } from "@/lib/services/org-translations";
import { parseFields } from "@/lib/services/forms";
import { issueFormToken } from "@/lib/public/forms";
import { Heading, Section, SafeLink, buttonCls, buttonOnPrimaryCls } from "./section";
import { MediaImage } from "./media-image";
import { Markup } from "./markup";
import { PublicForm } from "./public-form";
import { CarouselView, CountdownClock, LogoSliderView, TabsView } from "./interactive";
import type { RenderContext } from "./types";

const PLATFORM: Record<string, string> = { facebook: "Facebook", x: "X", linkedin: "LinkedIn", instagram: "Instagram", youtube: "YouTube", tiktok: "TikTok" };
const onDark = (bg: string) => bg === "primary" || bg === "dark";

export function CountdownBlock({ block }: { block: BlockOf<"countdown"> }) {
  const { props, style } = block;
  return (
    <Section style={style} label={props.heading || "Countdown"}>
      <Heading>{props.heading}</Heading>
      <CountdownClock target={props.target} endedText={props.endedText} />
    </Section>
  );
}

const LOGO_COLS = { "3": "sm:grid-cols-3", "4": "sm:grid-cols-4", "5": "sm:grid-cols-5", "6": "sm:grid-cols-3 md:grid-cols-6" } as const;
export function LogoGridBlock({ block, ctx }: { block: BlockOf<"logoGrid">; ctx: RenderContext }) {
  const { props, style } = block;
  // A library logo wins; otherwise an https image link. Items with neither (or a deleted/private library image) are skipped.
  const items = props.items.filter((i) => (i.mediaId && ctx.media.has(i.mediaId)) || (!i.mediaId && i.imageUrl));
  if (items.length === 0) return null;
  const cells = items.map((it, i) => {
    const imgCls = "mx-auto max-h-20 w-auto object-contain";
    const img = it.mediaId && ctx.media.has(it.mediaId)
      ? <MediaImage id={it.mediaId} media={ctx.media} className={imgCls} />
      // eslint-disable-next-line @next/next/no-img-element -- external https logo validated by the block schema
      : <img src={it.imageUrl} alt={it.name} loading="lazy" decoding="async" className={imgCls} />;
    return (
      <div key={`${it.mediaId ?? it.imageUrl}-${i}`} className="blk-card blk-logo flex h-full flex-col items-center justify-center gap-2 p-4 text-center">
        {it.tier ? <span className="text-[10px] font-bold uppercase tracking-widest opacity-70">{it.tier}</span> : null}
        {it.linkUrl ? <SafeLink href={it.linkUrl} className="block">{img}<span className="sr-only">{it.name}</span></SafeLink> : img}
        {it.name ? <span className="text-xs opacity-80">{it.name}</span> : null}
      </div>
    );
  });
  return (
    <Section style={style} label={props.heading || "Logos"}>
      <Heading>{props.heading}</Heading>
      {props.display === "slider" ? (
        <LogoSliderView perView={Number(props.columns)} label={props.heading || "Logos"}>{cells}</LogoSliderView>
      ) : (
        <ul className={cn("grid grid-cols-2 items-stretch gap-4", LOGO_COLS[props.columns])}>
          {cells.map((c, i) => <li key={i}>{c}</li>)}
        </ul>
      )}
    </Section>
  );
}

export function ButtonRowBlock({ block }: { block: BlockOf<"buttonRow"> }) {
  const { props, style } = block;
  const dark = onDark(style.background);
  return (
    <Section style={style} label={props.heading || "Links"}>
      <Heading>{props.heading}</Heading>
      <div className={cn("flex flex-wrap gap-3", props.align === "center" && "justify-center")}>
        {props.items.map((b, i) => (
          <SafeLink key={i} href={b.url} className={cn(dark ? buttonOnPrimaryCls : buttonCls, b.look === "outline" && "!bg-transparent border-2 !border-current !text-inherit")}>{b.label}</SafeLink>
        ))}
      </div>
    </Section>
  );
}

export function CarouselBlock({ block, ctx }: { block: BlockOf<"carousel">; ctx: RenderContext }) {
  const { props, style } = block;
  if (props.items.length === 0) return null;
  const slides = props.items.map((s, i) => (
    <figure key={i} className="blk-card overflow-hidden">
      <MediaImage id={s.imageId} media={ctx.media} className="aspect-[16/7] w-full object-cover" priority={i === 0} />
      {s.title || s.text ? (
        <figcaption className="p-5">
          {s.title ? <h3 className="text-lg font-semibold">{s.linkUrl ? <SafeLink href={s.linkUrl} className="hover:underline">{s.title}</SafeLink> : s.title}</h3> : null}
          {s.text ? <p className="mt-2 text-sm opacity-85">{s.text}</p> : null}
        </figcaption>
      ) : null}
    </figure>
  ));
  return (
    <Section style={style} label={props.heading || "Carousel"}>
      <Heading>{props.heading}</Heading>
      <CarouselView slides={slides} />
    </Section>
  );
}

export function TabsBlock({ block, vars }: { block: BlockOf<"tabs">; vars: MergeVars }) {
  const { props, style } = block;
  return (
    <Section style={style} label={props.heading || "Tabs"}>
      <Heading>{props.heading}</Heading>
      <TabsView titles={props.items.map((t) => t.title)} panels={props.items.map((t, i) => <Markup key={i} text={applyMergeTags(t.body, vars)} />)} />
    </Section>
  );
}

const SPACE = { sm: "h-4", md: "h-10", lg: "h-20", xl: "h-32" } as const;
export function SpacerBlock({ block }: { block: BlockOf<"spacer"> }) {
  const { props } = block;
  return (
    <div className={cn("flex items-center", SPACE[props.height])} aria-hidden="true">
      {props.line === "line" ? <hr className="mx-auto w-full max-w-6xl border-border px-4" /> : null}
    </div>
  );
}

export function EmbedBlock({ block }: { block: BlockOf<"embed"> }) {
  const { props, style } = block;
  if (!props.url) return null;
  return (
    <Section style={style} label={props.heading || "Embedded content"}>
      <Heading>{props.heading}</Heading>
      <iframe src={props.url} title={props.title || "Embedded content"} loading="lazy" style={{ height: props.height }} className="w-full border-0" referrerPolicy="strict-origin-when-cross-origin" sandbox="allow-scripts allow-same-origin allow-popups allow-forms" />
    </Section>
  );
}

export function MapBlock({ block }: { block: BlockOf<"map"> }) {
  const { props, style } = block;
  const src = `https://www.google.com/maps?q=${encodeURIComponent(props.address)}&output=embed`;
  return (
    <Section style={style} label={props.heading || "Map"}>
      <Heading>{props.heading}</Heading>
      <iframe src={src} title={`Map of ${props.address}`} loading="lazy" style={{ height: props.height }} className="w-full border-0" referrerPolicy="no-referrer-when-downgrade" allowFullScreen />
      <p className="mt-2 text-sm opacity-80">{props.address}</p>
    </Section>
  );
}

export function SocialFeedBlock({ block, ctx }: { block: BlockOf<"socialFeed">; ctx: RenderContext }) {
  const { props, style } = block;
  if (props.items.length === 0) return null;
  return (
    <Section style={style} label={props.heading || "Social posts"}>
      <Heading>{props.heading}</Heading>
      <ul className="grid gap-4 md:grid-cols-3">
        {props.items.map((p, i) => (
          <li key={i} className="blk-card overflow-hidden">
            <MediaImage id={p.imageId} media={ctx.media} className="aspect-[4/3] w-full object-cover" />
            <div className="p-4">
              <p className="text-xs font-bold uppercase tracking-widest opacity-70">{PLATFORM[p.platform]}{p.date ? ` · ${p.date}` : ""}</p>
              <p className="mt-2 whitespace-pre-line text-sm">{p.text}</p>
              {p.linkUrl ? <p className="mt-3 text-sm"><SafeLink href={p.linkUrl} className="underline">View post<span className="sr-only"> on {PLATFORM[p.platform]}</span></SafeLink></p> : null}
            </div>
          </li>
        ))}
      </ul>
    </Section>
  );
}

export function SocialLinksBlock({ block }: { block: BlockOf<"socialLinks"> }) {
  const { props, style } = block;
  if (props.items.length === 0) return null;
  const dark = onDark(style.background);
  return (
    <Section style={style} label={props.heading || "Social links"}>
      <Heading>{props.heading}</Heading>
      <ul className={cn("flex flex-wrap gap-3", props.align === "center" && "justify-center")}>
        {props.items.map((s, i) => <li key={i}><SafeLink href={s.url} className={dark ? buttonOnPrimaryCls : buttonCls}>{PLATFORM[s.platform]}</SafeLink></li>)}
      </ul>
    </Section>
  );
}

export async function NewsletterBlock({ block, ctx }: { block: BlockOf<"newsletter">; ctx: RenderContext }) {
  const { props, style } = block;
  const form = props.formId ? await db.formDefinition.findFirst({ where: { id: props.formId, siteId: ctx.siteId }, select: { id: true, status: true, fields: true, consentText: true } }) : null;
  if (!form) {
    return ctx.preview ? <Section style={style} label={props.heading}><Heading>{props.heading}</Heading><p className="rounded-md border border-dashed border-border p-4 text-sm opacity-70">No form selected. This note only shows in preview.</p></Section> : null;
  }
  const text = await messagesForSite(ctx.siteId);
  return (
    <Section style={style} label={props.heading || "Newsletter"}>
      <div className="mx-auto max-w-xl">
        <Heading>{props.heading}</Heading>
        {props.text ? <p className="mb-4 opacity-85">{props.text}</p> : null}
        {form.status === "PAUSED" ? <p role="status" className="blk-card p-4 text-sm">{text["forms.paused"]}</p> : <PublicForm formId={form.id} fields={parseFields(form.fields)} consentText={form.consentText} token={ctx.preview ? "preview" : issueFormToken(form.id)} disabled={ctx.preview} text={text} />}
      </div>
    </Section>
  );
}

export function ContactBlock({ block }: { block: BlockOf<"contact"> }) {
  const { props, style } = block;
  const rows: [string, React.ReactNode][] = [];
  if (props.email) rows.push(["Email", <a key="e" href={`mailto:${props.email}`} className="underline">{props.email}</a>]);
  if (props.phone) rows.push(["Phone", <a key="p" href={`tel:${props.phone.replace(/[^+\d]/g, "")}`} className="underline">{props.phone}</a>]);
  if (props.address) rows.push(["Address", <span key="a" className="whitespace-pre-line">{props.address}</span>]);
  if (props.hours) rows.push(["Hours", <span key="h" className="whitespace-pre-line">{props.hours}</span>]);
  if (rows.length === 0) return null;
  return (
    <Section style={style} label={props.heading || "Contact details"}>
      <Heading>{props.heading}</Heading>
      <dl className="grid gap-6 sm:grid-cols-2 lg:grid-cols-4">
        {rows.map(([k, v]) => <div key={k}><dt className="text-xs font-bold uppercase tracking-widest opacity-70">{k}</dt><dd className="mt-1">{v}</dd></div>)}
      </dl>
    </Section>
  );
}

export function VenueInfoBlock({ block, vars }: { block: BlockOf<"venueInfo">; vars: MergeVars }) {
  const { props, style } = block;
  return (
    <Section style={style} label={props.heading || "Information"}>
      <Heading>{props.heading}</Heading>
      <div className={cn("grid gap-8", props.columns.length > 1 && "md:grid-cols-2", props.columns.length > 2 && "lg:grid-cols-3", props.columns.length > 3 && "lg:grid-cols-4")}>
        {props.columns.map((c, i) => (
          <div key={i}>
            <h3 className="mb-3 text-lg font-bold">{c.title}</h3>
            <div className="text-sm"><Markup text={applyMergeTags(c.body, vars)} /></div>
          </div>
        ))}
      </div>
    </Section>
  );
}

export function DownloadsBlock({ block }: { block: BlockOf<"downloads"> }) {
  const { props, style } = block;
  return (
    <Section style={style} label={props.heading || "Downloads"}>
      <Heading>{props.heading}</Heading>
      <ul className="blk-card divide-y divide-border">
        {props.items.map((d, i) => (
          <li key={i} className="flex flex-wrap items-center justify-between gap-3 p-4">
            <div><p className="font-semibold">{d.label}</p>{d.description ? <p className="text-sm opacity-80">{d.description}</p> : null}</div>
            <SafeLink href={d.url} className={buttonCls}>Download<span className="sr-only"> {d.label}</span></SafeLink>
          </li>
        ))}
      </ul>
    </Section>
  );
}

export function TicketBannerBlock({ block }: { block: BlockOf<"ticketBanner"> }) {
  const { props, style } = block;
  return (
    <Section style={{ ...style, background: style.background === "none" ? "primary" : style.background }} label={props.heading}>
      <div className="mx-auto max-w-3xl text-center">
        {props.eyebrow ? <p className="mb-2 text-sm font-bold uppercase tracking-widest opacity-90">{props.eyebrow}</p> : null}
        <Heading>{props.heading}</Heading>
        {props.text ? <p className="mb-6 text-lg opacity-90">{props.text}</p> : null}
        <SafeLink href={props.buttonUrl} className={buttonOnPrimaryCls}>{props.buttonLabel}</SafeLink>
      </div>
    </Section>
  );
}

