export interface LandingHeroContent {
  badgeEmoji: string;
  badgeText: string;
  headingPrefix: string;
  headingHighlight: string;
  description: string;
  primaryCta: {
    label: string;
    url: string;
  };
  highlights: string[];
}

export interface LandingFeatureItem {
  title: string;
  description: string;
  icon: string;
}

export interface LandingFeaturesContent {
  heading: string;
  description: string;
  items: LandingFeatureItem[];
}

export interface LandingTechItem {
  name: string;
  description: string;
}

export interface LandingTechCategory {
  category: string;
  technologies: LandingTechItem[];
}

export interface LandingTechStackContent {
  heading: string;
  description: string;
  categories: LandingTechCategory[];
}

export interface LandingTestimonialItem {
  quote: string;
  name: string;
  role: string;
  company: string;
  avatarEmoji: string;
}

export interface LandingTestimonialsContent {
  heading: string;
  description: string;
  items: LandingTestimonialItem[];
}

export interface LandingLogoItem {
  name: string;
  accent: string;
}

export interface LandingLogoCloudContent {
  heading: string;
  items: LandingLogoItem[];
}

export interface LandingStatItem {
  value: string;
  label: string;
  description: string;
}

export interface LandingStatsContent {
  heading: string;
  description: string;
  items: LandingStatItem[];
}

export interface LandingPricingPlan {
  name: string;
  price: string;
  billingPeriod: string;
  description: string;
  badge: string;
  isHighlighted: boolean;
  ctaLabel: string;
  ctaUrl: string;
  features: string[];
}

export interface LandingPricingContent {
  heading: string;
  description: string;
  plans: LandingPricingPlan[];
}

export interface LandingFaqItem {
  question: string;
  answer: string;
}

export interface LandingFaqContent {
  heading: string;
  description: string;
  items: LandingFaqItem[];
}

export interface LandingCtaContent {
  heading: string;
  description: string;
  commandLabel: string;
  command: string;
}

export interface LandingBlockMetadata {
  id?: string;
  blockName?: string;
}

export interface LandingHeroBlock
  extends LandingHeroContent, LandingBlockMetadata {
  blockType: 'hero';
}

export interface LandingFeaturesBlock
  extends LandingFeaturesContent, LandingBlockMetadata {
  blockType: 'features';
}

export interface LandingTechStackBlock
  extends LandingTechStackContent, LandingBlockMetadata {
  blockType: 'techStack';
}

export interface LandingTestimonialsBlock
  extends LandingTestimonialsContent, LandingBlockMetadata {
  blockType: 'testimonials';
}

export interface LandingLogoCloudBlock
  extends LandingLogoCloudContent, LandingBlockMetadata {
  blockType: 'logoCloud';
}

export interface LandingStatsBlock
  extends LandingStatsContent, LandingBlockMetadata {
  blockType: 'stats';
}

export interface LandingPricingBlock
  extends LandingPricingContent, LandingBlockMetadata {
  blockType: 'pricing';
}

export interface LandingFaqBlock
  extends LandingFaqContent, LandingBlockMetadata {
  blockType: 'faq';
}

export interface LandingCtaBlock
  extends LandingCtaContent, LandingBlockMetadata {
  blockType: 'cta';
}

export type LandingPageBlock =
  | LandingHeroBlock
  | LandingFeaturesBlock
  | LandingTechStackBlock
  | LandingTestimonialsBlock
  | LandingLogoCloudBlock
  | LandingStatsBlock
  | LandingPricingBlock
  | LandingFaqBlock
  | LandingCtaBlock;

export interface LandingPageContent {
  layout: LandingPageBlock[];
}

interface PayloadTextRow {
  label: string;
}

interface PayloadLandingHeroRow extends Omit<LandingHeroBlock, 'highlights'> {
  highlights: PayloadTextRow[];
}

interface PayloadLandingPricingPlan extends Omit<
  LandingPricingPlan,
  'features'
> {
  features: PayloadTextRow[];
}

interface PayloadLandingPricingRow extends Omit<LandingPricingBlock, 'plans'> {
  plans: PayloadLandingPricingPlan[];
}

export type PayloadLandingPageRow =
  | PayloadLandingHeroRow
  | LandingFeaturesBlock
  | LandingTechStackBlock
  | LandingTestimonialsBlock
  | LandingLogoCloudBlock
  | LandingStatsBlock
  | PayloadLandingPricingRow
  | LandingFaqBlock
  | LandingCtaBlock;

export const defaultLandingHeroContent: LandingHeroContent = {
  badgeEmoji: '🚀',
  badgeText: 'Production-ready monorepo template',
  headingPrefix: 'Build Full-Stack Apps with',
  headingHighlight: 'convex-monorepo',
  description:
    'A Turborepo starter with Next.js, Expo, and self-hosted Convex. Ship web and mobile apps faster with shared code, type-safe backend, and complete control over your infrastructure.',
  primaryCta: {
    label: 'View Source Code',
    url: 'https://git.gbrown.org/gib/convex-monorepo',
  },
  highlights: ['TypeScript', 'Self-Hosted', 'Real-time', 'Auth Included'],
};

export const defaultLandingFeaturesContent: LandingFeaturesContent = {
  heading: 'Everything You Need to Ship Fast',
  description:
    'A complete monorepo template with all the tools and patterns you need for production-ready applications.',
  items: [
    {
      title: 'Turborepo',
      description:
        'Efficient build system with intelligent caching. Share code between web and mobile apps seamlessly.',
      icon: '⚡',
    },
    {
      title: 'Self-Hosted Convex',
      description:
        'Complete control over your data with self-hosted Convex backend. No vendor lock-in, deploy anywhere.',
      icon: '🏠',
    },
    {
      title: 'Next.js 16 + Expo',
      description:
        'Modern Next.js 16 with App Router for web, Expo 54 for mobile. One codebase, multiple platforms.',
      icon: '📱',
    },
    {
      title: 'Type-Safe Backend',
      description:
        'Fully type-safe queries and mutations with Convex. Auto-generated TypeScript types for the entire API.',
      icon: '🔒',
    },
    {
      title: 'Authentication Included',
      description:
        'OAuth with Authentik + custom password auth with email verification. Production-ready auth out of the box.',
      icon: '🔐',
    },
    {
      title: 'Real-time Updates',
      description:
        'Built-in real-time subscriptions with Convex reactive queries. No WebSocket configuration needed.',
      icon: '⚡',
    },
  ],
};

export const defaultLandingTechStackContent: LandingTechStackContent = {
  heading: 'Modern Tech Stack',
  description:
    'Built with the latest and greatest tools for maximum productivity and performance.',
  categories: [
    {
      category: 'Frontend',
      technologies: [
        {
          name: 'Next.js 16',
          description: 'React framework with App Router',
        },
        { name: 'Expo 54', description: 'React Native framework' },
        {
          name: 'React 19',
          description: 'Latest React with Server Components',
        },
        {
          name: 'Tailwind CSS v4',
          description: 'Utility-first CSS framework',
        },
        { name: 'shadcn/ui', description: 'Beautiful component library' },
      ],
    },
    {
      category: 'Backend',
      technologies: [
        { name: 'Convex', description: 'Self-hosted reactive backend' },
        {
          name: '@convex-dev/auth',
          description: 'Multi-provider authentication',
        },
        { name: 'UseSend', description: 'Self-hosted email service' },
        { name: 'Payload CMS', description: 'Embedded content platform' },
      ],
    },
    {
      category: 'Developer Tools',
      technologies: [
        { name: 'Turborepo', description: 'High-performance build system' },
        { name: 'TypeScript', description: 'Type-safe development' },
        { name: 'Bun', description: 'Fast package manager & runtime' },
        { name: 'Docker', description: 'Containerized deployment' },
      ],
    },
  ],
};

export const defaultLandingTestimonialsContent: LandingTestimonialsContent = {
  heading: 'What Clients Actually Care About',
  description:
    'The polished part is not just the frontend. Editors can shape the story, launch updates fast, and preview changes before they go live.',
  items: [
    {
      quote:
        'We changed homepage messaging during a sales call, hit save, and the preview updated instantly. That sold the workflow by itself.',
      name: 'Avery Stone',
      role: 'Founder',
      company: 'Northline Studio',
      avatarEmoji: '🧠',
    },
    {
      quote:
        'The admin feels like a real control panel, not a placeholder CMS. Our team could update sections without asking a developer.',
      name: 'Maya Torres',
      role: 'Marketing Lead',
      company: 'Signal Harbor',
      avatarEmoji: '✨',
    },
    {
      quote:
        'The live preview, drafts, and reusable blocks made the site feel custom while still being easy to maintain long term.',
      name: 'Jonah Reed',
      role: 'Product Consultant',
      company: 'Field Current',
      avatarEmoji: '🚀',
    },
  ],
};

export const defaultLandingLogoCloudContent: LandingLogoCloudContent = {
  heading: 'Designed For Modern Product Teams',
  items: [
    { name: 'Northline', accent: 'Strategy' },
    { name: 'Field Current', accent: 'Operations' },
    { name: 'Signal Harbor', accent: 'Marketing' },
    { name: 'Brightlayer', accent: 'SaaS' },
    { name: 'Blue Quarry', accent: 'Infrastructure' },
    { name: 'Keystone Lab', accent: 'Startups' },
  ],
};

export const defaultLandingStatsContent: LandingStatsContent = {
  heading: 'Built To Demo Well',
  description:
    'These are the kinds of outcomes you can point to when showing the template to clients.',
  items: [
    {
      value: '10x',
      label: 'Faster content updates',
      description:
        'Editors can revise sections without waiting on engineering.',
    },
    {
      value: '< 1 min',
      label: 'Preview feedback loop',
      description: 'Draft, tweak, and validate messaging almost instantly.',
    },
    {
      value: '100%',
      label: 'Self-hosted control',
      description: 'App, CMS, auth, and backend all stay under your control.',
    },
    {
      value: '1 repo',
      label: 'Shared product foundation',
      description:
        'Web app, backend, and future mobile work stay in one system.',
    },
  ],
};

export const defaultLandingPricingContent: LandingPricingContent = {
  heading: 'A Great Way To Pitch Productized Delivery',
  description:
    'Use pricing blocks to show packaged service tiers, subscriptions, or implementation options right inside the landing page builder.',
  plans: [
    {
      name: 'Starter',
      price: '$3k',
      billingPeriod: 'one-time',
      description: 'Launch a clean marketing site on top of the template fast.',
      badge: '',
      isHighlighted: false,
      ctaLabel: 'Book Intro Call',
      ctaUrl: '/sign-in',
      features: [
        'Custom homepage setup',
        'Payload editor training',
        'Auth + profile pages included',
      ],
    },
    {
      name: 'Growth',
      price: '$6k',
      billingPeriod: 'one-time',
      description:
        'Expand the template into a more tailored product marketing experience.',
      badge: 'Most Popular',
      isHighlighted: true,
      ctaLabel: 'Start Project',
      ctaUrl: '/sign-in',
      features: [
        'Everything in Starter',
        'Additional custom blocks',
        'SEO + analytics setup',
        'Admin workflow polish',
      ],
    },
    {
      name: 'Retainer',
      price: '$950',
      billingPeriod: '/month',
      description:
        'Keep iterating on content, features, and admin workflows after launch.',
      badge: '',
      isHighlighted: false,
      ctaLabel: 'Discuss Retainer',
      ctaUrl: '/sign-in',
      features: [
        'Monthly improvements',
        'Content support',
        'New sections and experiments',
      ],
    },
  ],
};

export const defaultLandingFaqContent: LandingFaqContent = {
  heading: 'Questions You Will Probably Get In A Demo',
  description:
    'A good FAQ block makes the editor feel complete and gives clients another obvious content type they can manage themselves.',
  items: [
    {
      question: 'Can non-developers reorder sections on the homepage?',
      answer:
        'Yes. The landing page now uses Payload blocks, so editors can add, remove, and reorder sections directly from the admin panel.',
    },
    {
      question: 'Does the live preview still work with blocks?',
      answer:
        'Yes. Drafts, autosave, and live preview continue to work while editing the block-based layout.',
    },
    {
      question: 'Can we create more block types later?',
      answer:
        'Absolutely. Testimonials, FAQ, pricing, stats, logo clouds, galleries, timelines, and case studies all fit naturally into this setup.',
    },
    {
      question: 'Is this only for the homepage?',
      answer:
        'No. The same pattern can power additional marketing pages, service pages, or even internal admin-managed microsites.',
    },
  ],
};

export const defaultLandingCtaContent: LandingCtaContent = {
  heading: 'Ready to Build Something Amazing?',
  description:
    'Clone the repository and start building your next project with everything pre-configured.',
  commandLabel: 'Quick Start',
  command:
    'git clone https://git.gbrown.org/gib/convex-monorepo.git\ncd convex-monorepo\nbun i',
};

const isRecord = (value: unknown): value is Record<string, unknown> => {
  return typeof value === 'object' && value !== null;
};

const sanitizeString = (value: unknown, fallback: string) => {
  return typeof value === 'string' && value.length > 0 ? value : fallback;
};

const sanitizeBoolean = (value: unknown, fallback: boolean) => {
  return typeof value === 'boolean' ? value : fallback;
};

const sanitizeOptionalString = (value: unknown) => {
  return typeof value === 'string' && value.length > 0 ? value : undefined;
};

const sanitizeStringArray = (value: unknown, fallback: string[]) => {
  if (!Array.isArray(value)) return fallback;

  const items = value
    .map((item) => {
      if (typeof item === 'string' && item.length > 0) return item;
      if (
        isRecord(item) &&
        typeof item.label === 'string' &&
        item.label.length > 0
      ) {
        return item.label;
      }

      return null;
    })
    .filter((item): item is string => item !== null);

  return items.length > 0 ? items : fallback;
};

const sanitizeBlockMetadata = (value: unknown): LandingBlockMetadata => {
  if (!isRecord(value)) return {};

  return {
    id: sanitizeOptionalString(value.id),
    blockName: sanitizeOptionalString(value.blockName),
  };
};

const sanitizeObjectArray = <T>(
  value: unknown,
  fallback: T[],
  mapItem: (item: Record<string, unknown>, index: number, fallbackItem: T) => T,
  emptyItem: T,
): T[] => {
  if (!Array.isArray(value)) return fallback;

  const items = value
    .map((item, index) => {
      if (!isRecord(item)) return null;

      return mapItem(item, index, fallback[index] ?? emptyItem);
    })
    .filter((item): item is T => item !== null);

  return items.length > 0 ? items : fallback;
};

const sanitizeFeatureItems = (
  value: unknown,
  fallback: LandingFeatureItem[],
) => {
  return sanitizeObjectArray(
    value,
    fallback,
    (item, _index, fallbackItem) => ({
      title: sanitizeString(item.title, fallbackItem.title),
      description: sanitizeString(item.description, fallbackItem.description),
      icon: sanitizeString(item.icon, fallbackItem.icon),
    }),
    { title: '', description: '', icon: '' },
  );
};

const sanitizeTechCategories = (
  value: unknown,
  fallback: LandingTechCategory[],
) => {
  return sanitizeObjectArray(
    value,
    fallback,
    (category, _index, fallbackCategory) => ({
      category: sanitizeString(category.category, fallbackCategory.category),
      technologies: sanitizeObjectArray(
        category.technologies,
        fallbackCategory.technologies,
        (technology, _technologyIndex, fallbackTechnology) => ({
          name: sanitizeString(technology.name, fallbackTechnology.name),
          description: sanitizeString(
            technology.description,
            fallbackTechnology.description,
          ),
        }),
        { name: '', description: '' },
      ),
    }),
    { category: '', technologies: [{ name: '', description: '' }] },
  );
};

const sanitizeTestimonials = (
  value: unknown,
  fallback: LandingTestimonialItem[],
) => {
  return sanitizeObjectArray(
    value,
    fallback,
    (item, _index, fallbackItem) => ({
      quote: sanitizeString(item.quote, fallbackItem.quote),
      name: sanitizeString(item.name, fallbackItem.name),
      role: sanitizeString(item.role, fallbackItem.role),
      company: sanitizeString(item.company, fallbackItem.company),
      avatarEmoji: sanitizeString(item.avatarEmoji, fallbackItem.avatarEmoji),
    }),
    {
      quote: '',
      name: '',
      role: '',
      company: '',
      avatarEmoji: '',
    },
  );
};

const sanitizeLogoItems = (value: unknown, fallback: LandingLogoItem[]) => {
  return sanitizeObjectArray(
    value,
    fallback,
    (item, _index, fallbackItem) => ({
      name: sanitizeString(item.name, fallbackItem.name),
      accent: sanitizeString(item.accent, fallbackItem.accent),
    }),
    { name: '', accent: '' },
  );
};

const sanitizeStatItems = (value: unknown, fallback: LandingStatItem[]) => {
  return sanitizeObjectArray(
    value,
    fallback,
    (item, _index, fallbackItem) => ({
      value: sanitizeString(item.value, fallbackItem.value),
      label: sanitizeString(item.label, fallbackItem.label),
      description: sanitizeString(item.description, fallbackItem.description),
    }),
    { value: '', label: '', description: '' },
  );
};

const sanitizePricingPlans = (
  value: unknown,
  fallback: LandingPricingPlan[],
) => {
  return sanitizeObjectArray(
    value,
    fallback,
    (plan, _index, fallbackPlan) => ({
      name: sanitizeString(plan.name, fallbackPlan.name),
      price: sanitizeString(plan.price, fallbackPlan.price),
      billingPeriod: sanitizeString(
        plan.billingPeriod,
        fallbackPlan.billingPeriod,
      ),
      description: sanitizeString(plan.description, fallbackPlan.description),
      badge: sanitizeString(plan.badge, fallbackPlan.badge),
      isHighlighted: sanitizeBoolean(
        plan.isHighlighted,
        fallbackPlan.isHighlighted,
      ),
      ctaLabel: sanitizeString(plan.ctaLabel, fallbackPlan.ctaLabel),
      ctaUrl: sanitizeString(plan.ctaUrl, fallbackPlan.ctaUrl),
      features: sanitizeStringArray(plan.features, fallbackPlan.features),
    }),
    {
      name: '',
      price: '',
      billingPeriod: '',
      description: '',
      badge: '',
      isHighlighted: false,
      ctaLabel: '',
      ctaUrl: '',
      features: [''],
    },
  );
};

const sanitizeFaqItems = (value: unknown, fallback: LandingFaqItem[]) => {
  return sanitizeObjectArray(
    value,
    fallback,
    (item, _index, fallbackItem) => ({
      question: sanitizeString(item.question, fallbackItem.question),
      answer: sanitizeString(item.answer, fallbackItem.answer),
    }),
    { question: '', answer: '' },
  );
};

const sanitizeHeroBlock = (value: unknown): LandingHeroBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'hero',
    ...metadata,
    badgeEmoji: sanitizeString(
      source.badgeEmoji,
      defaultLandingHeroContent.badgeEmoji,
    ),
    badgeText: sanitizeString(
      source.badgeText,
      defaultLandingHeroContent.badgeText,
    ),
    headingPrefix: sanitizeString(
      source.headingPrefix,
      defaultLandingHeroContent.headingPrefix,
    ),
    headingHighlight: sanitizeString(
      source.headingHighlight,
      defaultLandingHeroContent.headingHighlight,
    ),
    description: sanitizeString(
      source.description,
      defaultLandingHeroContent.description,
    ),
    primaryCta: {
      label: sanitizeString(
        isRecord(source.primaryCta) ? source.primaryCta.label : undefined,
        defaultLandingHeroContent.primaryCta.label,
      ),
      url: sanitizeString(
        isRecord(source.primaryCta) ? source.primaryCta.url : undefined,
        defaultLandingHeroContent.primaryCta.url,
      ),
    },
    highlights: sanitizeStringArray(
      source.highlights,
      defaultLandingHeroContent.highlights,
    ),
  };
};

const sanitizeFeaturesBlock = (value: unknown): LandingFeaturesBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'features',
    ...metadata,
    heading: sanitizeString(
      source.heading,
      defaultLandingFeaturesContent.heading,
    ),
    description: sanitizeString(
      source.description,
      defaultLandingFeaturesContent.description,
    ),
    items: sanitizeFeatureItems(
      source.items,
      defaultLandingFeaturesContent.items,
    ),
  };
};

const sanitizeTechStackBlock = (value: unknown): LandingTechStackBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'techStack',
    ...metadata,
    heading: sanitizeString(
      source.heading,
      defaultLandingTechStackContent.heading,
    ),
    description: sanitizeString(
      source.description,
      defaultLandingTechStackContent.description,
    ),
    categories: sanitizeTechCategories(
      source.categories,
      defaultLandingTechStackContent.categories,
    ),
  };
};

const sanitizeTestimonialsBlock = (
  value: unknown,
): LandingTestimonialsBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'testimonials',
    ...metadata,
    heading: sanitizeString(
      source.heading,
      defaultLandingTestimonialsContent.heading,
    ),
    description: sanitizeString(
      source.description,
      defaultLandingTestimonialsContent.description,
    ),
    items: sanitizeTestimonials(
      source.items,
      defaultLandingTestimonialsContent.items,
    ),
  };
};

const sanitizeLogoCloudBlock = (value: unknown): LandingLogoCloudBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'logoCloud',
    ...metadata,
    heading: sanitizeString(
      source.heading,
      defaultLandingLogoCloudContent.heading,
    ),
    items: sanitizeLogoItems(
      source.items,
      defaultLandingLogoCloudContent.items,
    ),
  };
};

const sanitizeStatsBlock = (value: unknown): LandingStatsBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'stats',
    ...metadata,
    heading: sanitizeString(source.heading, defaultLandingStatsContent.heading),
    description: sanitizeString(
      source.description,
      defaultLandingStatsContent.description,
    ),
    items: sanitizeStatItems(source.items, defaultLandingStatsContent.items),
  };
};

const sanitizePricingBlock = (value: unknown): LandingPricingBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'pricing',
    ...metadata,
    heading: sanitizeString(
      source.heading,
      defaultLandingPricingContent.heading,
    ),
    description: sanitizeString(
      source.description,
      defaultLandingPricingContent.description,
    ),
    plans: sanitizePricingPlans(
      source.plans,
      defaultLandingPricingContent.plans,
    ),
  };
};

const sanitizeFaqBlock = (value: unknown): LandingFaqBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'faq',
    ...metadata,
    heading: sanitizeString(source.heading, defaultLandingFaqContent.heading),
    description: sanitizeString(
      source.description,
      defaultLandingFaqContent.description,
    ),
    items: sanitizeFaqItems(source.items, defaultLandingFaqContent.items),
  };
};

const sanitizeCtaBlock = (value: unknown): LandingCtaBlock => {
  const metadata = sanitizeBlockMetadata(value);
  const source = isRecord(value) ? value : {};

  return {
    blockType: 'cta',
    ...metadata,
    heading: sanitizeString(source.heading, defaultLandingCtaContent.heading),
    description: sanitizeString(
      source.description,
      defaultLandingCtaContent.description,
    ),
    commandLabel: sanitizeString(
      source.commandLabel,
      defaultLandingCtaContent.commandLabel,
    ),
    command: sanitizeString(source.command, defaultLandingCtaContent.command),
  };
};

const sanitizeLayout = (value: unknown): LandingPageBlock[] => {
  if (!Array.isArray(value)) return [];

  return value
    .map((block) => {
      if (!isRecord(block) || typeof block.blockType !== 'string') return null;

      switch (block.blockType) {
        case 'hero':
          return sanitizeHeroBlock(block);
        case 'features':
          return sanitizeFeaturesBlock(block);
        case 'techStack':
          return sanitizeTechStackBlock(block);
        case 'testimonials':
          return sanitizeTestimonialsBlock(block);
        case 'logoCloud':
          return sanitizeLogoCloudBlock(block);
        case 'stats':
          return sanitizeStatsBlock(block);
        case 'pricing':
          return sanitizePricingBlock(block);
        case 'faq':
          return sanitizeFaqBlock(block);
        case 'cta':
          return sanitizeCtaBlock(block);
        default:
          return null;
      }
    })
    .filter((block): block is LandingPageBlock => block !== null);
};

const buildLegacyLandingPageLayout = (value: unknown): LandingPageBlock[] => {
  const source = isRecord(value) ? value : {};

  return [
    sanitizeHeroBlock(source.hero),
    sanitizeLogoCloudBlock(undefined),
    sanitizeFeaturesBlock(source.features),
    sanitizeStatsBlock(undefined),
    sanitizeTechStackBlock(source.techStack),
    sanitizeTestimonialsBlock(undefined),
    sanitizePricingBlock(undefined),
    sanitizeFaqBlock(undefined),
    sanitizeCtaBlock(source.cta),
  ];
};

export const createDefaultLandingPageLayout = (): LandingPageBlock[] => {
  return buildLegacyLandingPageLayout({
    hero: defaultLandingHeroContent,
    features: defaultLandingFeaturesContent,
    techStack: defaultLandingTechStackContent,
    cta: defaultLandingCtaContent,
  });
};

export const createDefaultLandingPageLayoutForPayload =
  (): PayloadLandingPageRow[] => {
    return [
      {
        blockType: 'hero',
        ...defaultLandingHeroContent,
        highlights: defaultLandingHeroContent.highlights.map((label) => ({
          label,
        })),
      },
      {
        blockType: 'logoCloud',
        ...defaultLandingLogoCloudContent,
      },
      {
        blockType: 'features',
        ...defaultLandingFeaturesContent,
      },
      {
        blockType: 'stats',
        ...defaultLandingStatsContent,
      },
      {
        blockType: 'techStack',
        ...defaultLandingTechStackContent,
      },
      {
        blockType: 'testimonials',
        ...defaultLandingTestimonialsContent,
      },
      {
        blockType: 'pricing',
        ...defaultLandingPricingContent,
        plans: defaultLandingPricingContent.plans.map((plan) => ({
          ...plan,
          features: plan.features.map((label) => ({ label })),
        })),
      },
      {
        blockType: 'faq',
        ...defaultLandingFaqContent,
      },
      {
        blockType: 'cta',
        ...defaultLandingCtaContent,
      },
    ];
  };

export const defaultLandingPageContent: LandingPageContent = {
  layout: createDefaultLandingPageLayout(),
};

export const mergeLandingPageContent = (value: unknown): LandingPageContent => {
  const source = isRecord(value) ? value : {};
  const layout = sanitizeLayout(source.layout);

  return {
    layout: layout.length > 0 ? layout : buildLegacyLandingPageLayout(source),
  };
};
