import { z } from 'zod'

// ----- Shared primitives -----

export const imageSchema = z.object({
  src: z.string().min(1),
  alt: z.string().min(1),
  width: z.number().optional(),
  height: z.number().optional(),
})

export const ctaSchema = z.object({
  label: z.string().min(1),
  href: z.string().min(1),
  variant: z.enum(['primary', 'secondary']).optional().default('primary'),
})

// ----- Section schemas -----

export const videoSchema = z.object({
  src: z.string().min(1),
  poster: z.string().optional(),
})

export const heroSectionSchema = z.object({
  title: z.string().min(1),
  subtitle: z.string().optional(),
  description: z.string().optional(),
  image: imageSchema.optional(),
  video: videoSchema.optional(),
  youtubeUrl: z.string().url().optional(),
  ctas: z.array(ctaSchema).optional(),
})

export const contentBlockSchema = z.object({
  heading: z.string().min(1),
  body: z.string().min(1),
  image: imageSchema.optional(),
  icon: z.string().optional(),
})

export const contentBlocksSectionSchema = z.object({
  heading: z.string().optional(),
  blocks: z.array(contentBlockSchema).min(1),
  columns: z.enum(['2', '3']).optional().default('3'),
})

export const socialProofSectionSchema = z.object({
  heading: z.string().optional(),
  logos: z.array(imageSchema).optional(),
  testimonial: z
    .object({
      quote: z.string().min(1),
      author: z.string().min(1),
      role: z.string().optional(),
      avatar: imageSchema.optional(),
    })
    .optional(),
  stats: z
    .array(
      z.object({
        value: z.string().min(1),
        label: z.string().min(1),
      })
    )
    .optional(),
})

export const textBodySectionSchema = z.object({
  content: z.string().min(1),
})

const sectionBase = {
  id: z.string().optional(),
  className: z.string().optional(),
}

export const singleColumnSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('single-column'),
  title: z.string().min(1),
  description: z.string().optional(),
  children: z.any().optional(),
})

export const twoColumnSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('two-column'),
  title: z.string().optional(),
  description: z.string().optional(),
  children: z.any().optional(),
})

export const threeColumnSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('three-column'),
  title: z.string().optional(),
  description: z.string().optional(),
  children: z.any().optional(),
})

// ----- Form field schemas -----

/**
 * Conditional visibility rule: a field is visible only when the referenced
 * field's current value satisfies all of the supplied criteria.
 *
 * - `equals` / `notEquals` — strict string compare against the live value.
 * - `in` / `notIn` — membership check against a list of values.
 * - `truthy` — when `true`, requires a non-empty value; when `false`, requires empty.
 *
 * Multiple criteria within the same `showWhen` are combined with AND. Hidden
 * fields are excluded from the submitted payload.
 */
export const showWhenSchema = z
  .object({
    field: z.string().min(1),
    equals: z.string().optional(),
    notEquals: z.string().optional(),
    in: z.array(z.string()).optional(),
    notIn: z.array(z.string()).optional(),
    truthy: z.boolean().optional(),
  })
  .refine(
    (v) =>
      v.equals !== undefined ||
      v.notEquals !== undefined ||
      v.in !== undefined ||
      v.notIn !== undefined ||
      v.truthy !== undefined,
    { message: 'showWhen must include at least one of: equals, notEquals, in, notIn, truthy' }
  )

const formFieldBase = z.object({
  name: z.string().min(1),
  label: z.string().min(1),
  /** Helper text rendered beneath the input. */
  description: z.string().optional(),
  placeholder: z.string().optional(),
  required: z.boolean().optional().default(false),
  half: z.boolean().optional().default(false),
  showWhen: showWhenSchema.optional(),
})

export const textFieldSchema = formFieldBase.extend({
  type: z.literal('text'),
})

export const urlFieldSchema = formFieldBase.extend({
  type: z.literal('url'),
})

export const emailFieldSchema = formFieldBase.extend({
  type: z.literal('email'),
})

export const textareaFieldSchema = formFieldBase.extend({
  type: z.literal('textarea'),
  rows: z.number().optional().default(4),
})

export const selectFieldSchema = formFieldBase.extend({
  type: z.literal('select'),
  options: z.array(z.object({ label: z.string(), value: z.string() })).min(1),
})

export const checkboxFieldSchema = formFieldBase.extend({
  type: z.literal('checkbox'),
})

export const formFieldSchema = z.discriminatedUnion('type', [
  textFieldSchema,
  urlFieldSchema,
  emailFieldSchema,
  textareaFieldSchema,
  selectFieldSchema,
  checkboxFieldSchema,
])

// ----- Form CRM config schemas -----

/**
 * Matches a UUID or a bare 32-char hex ID (Notion's database IDs often come
 * without dashes). Used for values interpolated into outbound API URLs — the
 * `crm` config travels over the server-action wire and must be treated as
 * untrusted input.
 */
const uuidLikeIdSchema = z.union([
  z.string().uuid(),
  z.string().regex(/^[0-9a-f]{32}$/i, 'Must be a 32-character hex ID'),
])

export const hubspotFormConfigSchema = z.object({
  /**
   * HubSpot form GUID. The portal ID is read from HUBSPOT_PORTAL_ID env var.
   */
  formGuid: uuidLikeIdSchema,
  /**
   * Map each form field `name` to a HubSpot field name.
   * If omitted, the form field name is used as-is.
   * Example: { workEmail: 'email', companyName: 'company' }
   */
  fieldMap: z.record(z.string(), z.string()).optional(),
  /** Legal consent text for GDPR. */
  consent: z.string().optional(),
})

export const customerioFormConfigSchema = z.object({
  /**
   * Event name sent to Customer.io on submit.
   * Credentials are read from CUSTOMERIO_SITE_ID and CUSTOMERIO_API_KEY env vars.
   */
  event: z.string().min(1),
  /**
   * Map each form field `name` to a Customer.io profile attribute.
   * Fields listed here are added to the contact profile via `identify`.
   * Example: { workEmail: 'email', firstName: 'first_name' }
   */
  profileMap: z.record(z.string(), z.string()).optional(),
  /**
   * Static properties merged into the Customer.io track() event payload.
   * Use this for fixed values that aren't form fields (e.g. event_name, source).
   * Example: { event_name: 'Stripe Sessions 2026 Exec Dinner' }
   */
  staticProperties: z.record(z.string(), z.unknown()).optional(),
})

export const notionFormConfigSchema = z.object({
  /**
   * Notion database ID to create a page in. The integration token is read
   * from the NOTION_FORMS_API_KEY env var and must have write access to the database.
   */
  database_id: uuidLikeIdSchema,
  /**
   * Map each form field `name` to a Notion database column name.
   * Only fields listed here are sent. Property types (title, rich_text,
   * email, etc.) are auto-detected from the database schema.
   * Example: { email_address: 'email', first_name: 'first_name' }
   */
  columnMap: z.record(z.string(), z.string()).optional(),
  /**
   * Static properties merged into the Notion page. Keys must match column
   * names in the target database.
   * Example: { source: 'Website Go Page' }
   */
  staticProperties: z.record(z.string(), z.unknown()).optional(),
})

export const formCrmConfigSchema = z
  .object({
    hubspot: hubspotFormConfigSchema.optional(),
    customerio: customerioFormConfigSchema.optional(),
    notion: notionFormConfigSchema.optional(),
  })
  .refine((v) => v.hubspot || v.customerio || v.notion, {
    message: 'At least one CRM provider (hubspot, customerio, or notion) must be configured',
  })

export const formSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('form'),
  title: z.string().optional(),
  description: z.string().optional(),
  fields: z.array(formFieldSchema).min(1),
  submitLabel: z.string().min(1),
  disclaimer: z.string().optional(),
  /** Message shown after a successful submission. Defaults to a generic thank-you message. */
  successMessage: z.string().optional(),
  /** URL to redirect the user to after a successful submission. When set, overrides successMessage. */
  successRedirect: z.string().optional(),
  /** CRM integration config. When provided, form submissions are sent to the configured providers. */
  crm: formCrmConfigSchema.optional(),
})

export const featureGridItemSchema = z.object({
  icon: z.string().optional(),
  title: z.string().min(1),
  description: z.string().min(1),
})

export const featureGridSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('feature-grid'),
  title: z.string().optional(),
  description: z.string().optional(),
  columns: z
    .union([z.literal(1), z.literal(2), z.literal(3)])
    .optional()
    .default(3),
  items: z.array(featureGridItemSchema).min(1).max(6),
})

export const metricItemSchema = z.object({
  label: z.string().min(1),
  value: z.string().min(1),
})

export const metricsSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('metrics'),
  items: z.array(metricItemSchema).min(1).max(5),
})

export const tweetsSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('tweets'),
  title: z.string().optional(),
  description: z.string().optional(),
  ctas: z.array(ctaSchema).optional(),
})

export const faqItemSchema = z.object({
  question: z.string().min(1),
  answer: z.string().min(1),
})

export const faqSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('faq'),
  title: z.string().optional(),
  description: z.string().optional(),
  items: z.array(faqItemSchema).min(1),
})

export const codeFileSchema = z.object({
  filename: z.string().min(1),
  code: z.string().min(1),
  language: z.string().optional().default('sql'),
})

export const codeBlockSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('code-block'),
  title: z.string().optional(),
  description: z.string().optional(),
  /** Single-file mode */
  code: z.string().optional(),
  language: z.string().optional().default('sql'),
  filename: z.string().optional(),
  /** Multi-file mode — takes precedence over code/filename/language when set */
  files: z.array(codeFileSchema).optional(),
})

export const stepItemSchema = z.object({
  title: z.string().min(1),
  description: z.string().optional(),
  content: z.any().optional(),
  icon: z.string().optional(),
})

export const stepsSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('steps'),
  title: z.string().optional(),
  description: z.string().optional(),
  items: z.array(stepItemSchema).min(1),
})

export const quoteSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('quote'),
  quote: z.string().min(1),
  author: z.string().min(1),
  role: z.string().optional(),
  avatar: imageSchema.optional(),
})

export const hubspotMeetingSectionSchema = z.object({
  ...sectionBase,
  type: z.literal('hubspot-meeting'),
  title: z.string().optional(),
  description: z.string().optional(),
  /** The HubSpot meeting link path, e.g. "your-name/meeting-type" */
  meetingSlug: z.string().min(1),
})

// ----- Dynamic sections -----

export const goSectionSchema = z.discriminatedUnion('type', [
  singleColumnSectionSchema,
  twoColumnSectionSchema,
  threeColumnSectionSchema,
  formSectionSchema,
  featureGridSectionSchema,
  metricsSectionSchema,
  tweetsSectionSchema,
  faqSectionSchema,
  codeBlockSectionSchema,
  stepsSectionSchema,
  quoteSectionSchema,
  hubspotMeetingSectionSchema,
])

// ----- Page-level schemas -----

export const metadataSchema = z.object({
  title: z.string().min(1),
  description: z.string().min(1),
  ogImage: z.string().optional(),
  noIndex: z.boolean().optional().default(true),
})

// ----- Page schemas -----

const goPageBaseSchema = z.object({
  slug: z.string().min(1),
  metadata: metadataSchema,
  hero: heroSectionSchema,
  sections: z.array(goSectionSchema).optional(),
  publishedAt: z.string().optional(),
})

export const leadGenPageSchema = goPageBaseSchema.extend({
  template: z.literal('lead-gen'),
})

export const thankYouPageSchema = goPageBaseSchema.extend({
  template: z.literal('thank-you'),
})

export const legalPageSchema = goPageBaseSchema.extend({
  template: z.literal('legal'),
  effectiveDate: z.string().optional(),
  body: z.string().min(1),
})

export const goPageSchema = z.discriminatedUnion('template', [
  leadGenPageSchema,
  thankYouPageSchema,
  legalPageSchema,
])

// ----- Inferred types -----

export type GoImage = z.infer<typeof imageSchema>
export type GoVideo = z.infer<typeof videoSchema>
export type GoCta = z.infer<typeof ctaSchema>
export type GoHeroSection = z.infer<typeof heroSectionSchema>
export type GoContentBlock = z.infer<typeof contentBlockSchema>
export type GoContentBlocksSection = z.infer<typeof contentBlocksSectionSchema>
export type GoSocialProofSection = z.infer<typeof socialProofSectionSchema>
export type GoTextBodySection = z.infer<typeof textBodySectionSchema>
export type GoSingleColumnSection = z.infer<typeof singleColumnSectionSchema>
export type GoTwoColumnSection = z.infer<typeof twoColumnSectionSchema>
export type GoThreeColumnSection = z.infer<typeof threeColumnSectionSchema>
export type GoFormField = z.infer<typeof formFieldSchema>
export type GoFormFieldShowWhen = z.infer<typeof showWhenSchema>
export type GoFormSection = z.infer<typeof formSectionSchema>
export type GoHubSpotFormConfig = z.infer<typeof hubspotFormConfigSchema>
export type GoCustomerIOFormConfig = z.infer<typeof customerioFormConfigSchema>
export type GoNotionFormConfig = z.infer<typeof notionFormConfigSchema>
export type GoFormCrmConfig = z.infer<typeof formCrmConfigSchema>
export type GoFeatureGridItem = z.infer<typeof featureGridItemSchema>
export type GoFeatureGridSection = z.infer<typeof featureGridSectionSchema>
export type GoMetricItem = z.infer<typeof metricItemSchema>
export type GoMetricsSection = z.infer<typeof metricsSectionSchema>
export type GoTweetsSection = z.infer<typeof tweetsSectionSchema>
export type GoFaqItem = z.infer<typeof faqItemSchema>
export type GoFaqSection = z.infer<typeof faqSectionSchema>
export type GoCodeFile = z.infer<typeof codeFileSchema>
export type GoCodeBlockSection = z.infer<typeof codeBlockSectionSchema>
export type GoStepItem = z.infer<typeof stepItemSchema>
export type GoStepsSection = z.infer<typeof stepsSectionSchema>
export type GoQuoteSection = z.infer<typeof quoteSectionSchema>
export type GoHubSpotMeetingSection = z.infer<typeof hubspotMeetingSectionSchema>
export type GoSection = z.infer<typeof goSectionSchema>
export type GoMetadata = z.infer<typeof metadataSchema>

export type GoPage = z.infer<typeof goPageSchema>
export type LeadGenPage = z.infer<typeof leadGenPageSchema>
export type ThankYouPage = z.infer<typeof thankYouPageSchema>
export type LegalPage = z.infer<typeof legalPageSchema>

/** Input type for registry files — fields with defaults are optional */
export type GoPageInput = z.input<typeof goPageSchema>
