import { z } from 'zod'
import { UuidSchema, NonEmptyStringSchema } from '../../platform/utils/validation'
import { CredentialRequirementSchema, RecordColumnConfigSchema } from '../../organization-model/domains/prospecting'
export { CrmPriorityBucketKeySchema, CrmPriorityBucketOverrideSchema, CrmPriorityOverrideSchema } from './crm-priority'
export type { CrmPriorityBucketOverride, CrmPriorityOverride, ResolvedCrmPriorityRuleConfig } from './crm-priority'

export const ProcessingStageStatusSchema = z.enum(['success', 'no_result', 'skipped', 'error'])

export const LeadGenStageKeySchema = z.string().trim().min(1)

export const LeadGenActionKeySchema = z.string().trim().min(1)

// CRM stage/state catalogs are model-owned (authored in the tenant-owned organization model package
// canonicalOrganizationModel). The published core schema validates only the
// transport shape; closed-catalog membership is enforced by the caller/API
// layer via model-injected validators (mirrors LeadGenStageKeySchema).
export const CrmStageKeySchema = z.string().trim().min(1)
export const CrmStateKeySchema = z.string().trim().min(1)

export const ProcessingStateEntrySchema = z
  .object({
    status: ProcessingStageStatusSchema,
    data: z.unknown().optional()
  })
  .passthrough()

export const ProcessingStateSchema = z.record(LeadGenStageKeySchema, ProcessingStateEntrySchema)
export const CompanyProcessingStateSchema = ProcessingStateSchema
export const ContactProcessingStateSchema = ProcessingStateSchema

/**
 * Deal Management API Schemas
 *
 * Request/response validation for /api/deals surface.
 * Used by both the API route handlers and the frontend hooks.
 *
 * Table mapping:
 *   acq_deals       -> DealSchemas (list/detail)
 *   acq_deal_notes  -> DealSchemas (note shapes)
 *   acq_deal_tasks  -> DealSchemas (task shapes)
 */

// ---------------------------------------------------------------------------
// Enum literals (must match DB CHECK constraints exactly)
// ---------------------------------------------------------------------------

export const DealStageSchema = CrmStageKeySchema

export const AcqDealTaskKindSchema = z.enum(['call', 'email', 'meeting', 'other'])

// ---------------------------------------------------------------------------
// Params
// ---------------------------------------------------------------------------

export const DealIdParamsSchema = z.object({
  dealId: UuidSchema
})

export const DealTaskIdParamsSchema = z.object({
  dealId: UuidSchema,
  taskId: UuidSchema
})

// ---------------------------------------------------------------------------
// Query schemas (coerce strings from query params)
// ---------------------------------------------------------------------------

export const ListDealsQuerySchema = z
  .object({
    stage: DealStageSchema.optional(),
    list: UuidSchema.optional(),
    batch: z.string().trim().min(1).max(255).optional(),
    staleSince: z.string().datetime().optional(),
    search: z.string().optional(),
    limit: z.coerce.number().int().positive().default(50),
    offset: z.coerce.number().int().min(0).default(0)
  })
  .strict()

export const DealLookupQuerySchema = z
  .object({
    search: z.string().trim().min(1).max(200).optional(),
    limit: z.coerce.number().int().min(1).max(25).default(10)
  })
  .strict()

export const ListDealTasksDueQuerySchema = z
  .object({
    window: z.enum(['overdue', 'today', 'today_and_overdue', 'upcoming']).optional(),
    assigneeUserId: UuidSchema.optional()
  })
  .strict()

// ---------------------------------------------------------------------------
// Request body schemas (all use .strict() — rejects unknown fields)
// ---------------------------------------------------------------------------

export const CreateDealNoteRequestSchema = z
  .object({
    body: z.string().trim().min(1).max(10000)
  })
  .strict()

export const CreateDealTaskRequestSchema = z
  .object({
    title: z.string().trim().min(1).max(255),
    description: z.string().nullable().optional(),
    kind: AcqDealTaskKindSchema.optional(),
    dueAt: z.string().datetime().nullable().optional(),
    assigneeUserId: UuidSchema.nullable().optional()
  })
  .strict()

export const TransitionItemRequestSchema = z
  .object({
    pipelineKey: z.string().min(1),
    stageKey: z.string().min(1),
    stateKey: z.string().min(1).nullable().optional(),
    reason: z.string().optional(),
    expectedUpdatedAt: z.string().datetime().optional()
  })
  .strict()

export const CrmTransitionItemRequestSchema = z
  .object({
    pipelineKey: z.string().min(1),
    stageKey: CrmStageKeySchema,
    stateKey: CrmStateKeySchema.nullable().optional(),
    reason: z.string().optional(),
    expectedUpdatedAt: z.string().datetime().optional()
  })
  .strict()

export const TransitionDealStateRequestSchema = z
  .object({
    stateKey: CrmStateKeySchema,
    reason: z.string().optional(),
    expectedUpdatedAt: z.string().datetime().optional()
  })
  .strict()

export const ExecuteActionParamsSchema = z
  .object({
    dealId: UuidSchema,
    actionKey: NonEmptyStringSchema
  })
  .strict()

export const ExecuteActionRequestSchema = z
  .object({
    payload: z.record(z.string(), z.unknown()).optional()
  })
  .strict()

// ---------------------------------------------------------------------------
// Response schemas (no .strict() — allows forward-compatible additions)
// ---------------------------------------------------------------------------

/**
 * Contact summary nested inside DealListItem / DealDetailResponse.
 * Matches the joined shape returned by useDeals / useDealDetail Supabase queries.
 */
export const DealContactSummarySchema = z.object({
  id: z.string(),
  first_name: z.string().nullable(),
  last_name: z.string().nullable(),
  email: z.string(),
  title: z.string().nullable(),
  headline: z.string().nullable(),
  linkedin_url: z.string().nullable(),
  processing_state: ProcessingStateSchema.nullable(),
  enrichment_data: z.record(z.string(), z.unknown()).nullable(),
  company: z
    .object({
      id: z.string(),
      name: z.string(),
      domain: z.string().nullable(),
      website: z.string().nullable(),
      linkedin_url: z.string().nullable(),
      segment: z.string().nullable(),
      category: z.string().nullable(),
      num_employees: z.number().nullable()
    })
    .nullable()
})

export const DealPrioritySchema = z.object({
  bucketKey: z.enum(['needs_response', 'follow_up_due', 'waiting', 'stale', 'closed_low']),
  rank: z.number().int(),
  label: z.string(),
  color: z.string(),
  reason: z.string(),
  latestActivityAt: z.string().nullable(),
  nextActionAt: z.string().nullable()
})

/**
 * Deal list item with joined contact (and company via contact).
 * Matches DealListItem from @repo/core types.
 */
export const DealListItemSchema = z.object({
  // acq_deals columns
  id: z.string(),
  organization_id: z.string(),
  client_id: z.string().nullable().optional(),
  contact_id: z.string().nullable(),
  contact_email: z.string(),
  pipeline_key: z.string(),
  stage_key: z.string().nullable(),
  state_key: z.string().nullable(),
  activity_log: z.unknown(),
  discovery_data: z.unknown().nullable(),
  discovery_submitted_at: z.string().nullable(),
  discovery_submitted_by: z.string().nullable(),
  proposal_data: z.unknown().nullable(),
  proposal_sent_at: z.string().nullable(),
  proposal_pdf_url: z.string().nullable(),
  signature_envelope_id: z.string().nullable(),
  source_list_id: z.string().nullable(),
  source_type: z.string().nullable(),
  initial_fee: z.number().nullable(),
  monthly_fee: z.number().nullable(),
  closed_lost_at: z.string().nullable(),
  closed_lost_reason: z.string().nullable(),
  created_at: z.string(),
  updated_at: z.string(),
  priority: DealPrioritySchema,
  ownership: z.enum(['us', 'them']).nullable(),
  nextAction: z.string().nullable(),
  // joined relation
  contact: DealContactSummarySchema.nullable()
})

export const DealListResponseSchema = z.object({
  data: z.array(DealListItemSchema),
  total: z.number().int(),
  limit: z.number().int(),
  offset: z.number().int()
})

export const DealStageSummarySchema = z.object({
  stage: z.string(),
  count: z.number().int(),
  totalValue: z.number(),
  oldestUpdatedAt: z.string().nullable(),
  newestUpdatedAt: z.string().nullable()
})

export const StaleDealSummarySchema = z.object({
  id: z.string(),
  contactEmail: z.string(),
  stageKey: z.string(),
  updatedAt: z.string(),
  daysStale: z.number().int()
})

export const DealSummaryResponseSchema = z.object({
  totalDeals: z.number().int(),
  openDeals: z.number().int(),
  wonDeals: z.number().int(),
  lostDeals: z.number().int(),
  winRate: z.number(),
  avgDealSize: z.number(),
  totalPipelineValue: z.number(),
  stageSummary: z.array(DealStageSummarySchema),
  staleDeals: z.array(StaleDealSummarySchema)
})

export const DealLookupItemSchema = z.object({
  id: z.string(),
  contactEmail: z.string(),
  stageKey: z.string().nullable(),
  updatedAt: z.string(),
  contactName: z.string().nullable(),
  companyName: z.string().nullable(),
  displayLabel: z.string()
})

export const DealLookupResponseSchema = z.array(DealLookupItemSchema)

export const ConversationMessageSchema = z.object({
  id: z.string(),
  direction: z.enum(['inbound', 'outbound']),
  fromEmail: z.string(),
  toEmail: z.string(),
  subject: z.string().nullable(),
  body: z.string(),
  sentAt: z.string().nullable()
})

export const DealConversationSchema = z.object({
  messages: z.array(ConversationMessageSchema)
})

export const DealLineageListRefSchema = z.object({
  id: z.string(),
  name: z.string(),
  status: z.string()
})

export const DealLineageProjectRefSchema = z.object({
  id: z.string(),
  name: z.string(),
  kind: z.string(),
  status: z.string(),
  updatedAt: z.string()
})

export const DealLineageClientRefSchema = z.object({
  id: z.string(),
  name: z.string(),
  status: z.string()
})

export const DealLineageSchema = z.object({
  list: DealLineageListRefSchema.nullable(),
  projects: z.array(DealLineageProjectRefSchema),
  client: DealLineageClientRefSchema.nullable()
})

/**
 * Deal detail shape — currently the same as a list item (full joined record).
 * Additive fields keep existing DealListItem callers compatible.
 */
export const DealDetailResponseSchema = DealListItemSchema.extend({
  conversation: DealConversationSchema,
  lineage: DealLineageSchema.optional()
})

/**
 * Single acq_deal_notes row (camelCase API representation).
 */
export const DealNoteResponseSchema = z.object({
  id: z.string(),
  dealId: z.string(),
  organizationId: z.string(),
  authorUserId: z.string().nullable(),
  body: z.string(),
  createdAt: z.string(),
  updatedAt: z.string()
})

export const DealNoteListResponseSchema = z.array(DealNoteResponseSchema)

/**
 * Single acq_deal_tasks row (camelCase API representation).
 * Matches AcqDealTask domain type from types.ts.
 */
export const DealTaskResponseSchema = z.object({
  id: z.string(),
  organizationId: z.string(),
  dealId: z.string(),
  title: z.string(),
  description: z.string().nullable(),
  kind: AcqDealTaskKindSchema,
  dueAt: z.string().nullable(),
  assigneeUserId: z.string().nullable(),
  completedAt: z.string().nullable(),
  completedByUserId: z.string().nullable(),
  createdAt: z.string(),
  updatedAt: z.string(),
  createdByUserId: z.string().nullable()
})

export const DealTaskListResponseSchema = z.array(DealTaskResponseSchema)

// ---------------------------------------------------------------------------
// Bundled export
// ---------------------------------------------------------------------------

export const DealSchemas = {
  // Primitives
  CrmStageKey: CrmStageKeySchema,
  CrmStateKey: CrmStateKeySchema,
  DealStage: DealStageSchema,

  // Params
  DealIdParams: DealIdParamsSchema,
  DealTaskIdParams: DealTaskIdParamsSchema,

  // Queries
  ListDealsQuery: ListDealsQuerySchema,
  DealLookupQuery: DealLookupQuerySchema,
  ListDealTasksDueQuery: ListDealTasksDueQuerySchema,

  // Request bodies
  CreateDealNoteRequest: CreateDealNoteRequestSchema,
  CreateDealTaskRequest: CreateDealTaskRequestSchema,
  TransitionItemRequest: CrmTransitionItemRequestSchema,
  TransitionDealStateRequest: TransitionDealStateRequestSchema,
  ExecuteActionParams: ExecuteActionParamsSchema,
  ExecuteActionRequest: ExecuteActionRequestSchema,

  // Responses
  DealPriority: DealPrioritySchema,
  DealListResponse: DealListResponseSchema,
  DealSummaryResponse: DealSummaryResponseSchema,
  DealLookupResponse: DealLookupResponseSchema,
  ConversationMessage: ConversationMessageSchema,
  DealLineageListRef: DealLineageListRefSchema,
  DealLineageProjectRef: DealLineageProjectRefSchema,
  DealLineageClientRef: DealLineageClientRefSchema,
  DealLineage: DealLineageSchema,
  DealDetailResponse: DealDetailResponseSchema,
  DealNoteResponse: DealNoteResponseSchema,
  DealNoteListResponse: DealNoteListResponseSchema,
  DealTaskResponse: DealTaskResponseSchema,
  DealTaskListResponse: DealTaskListResponseSchema
}

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

export type DealStage = z.infer<typeof DealStageSchema>
export type CrmStageKey = z.infer<typeof CrmStageKeySchema>
export type CrmStateKey = z.infer<typeof CrmStateKeySchema>
export type AcqDealTaskKind = z.infer<typeof AcqDealTaskKindSchema>
export type DealIdParams = z.infer<typeof DealIdParamsSchema>
export type DealTaskIdParams = z.infer<typeof DealTaskIdParamsSchema>
export type ListDealsQuery = z.infer<typeof ListDealsQuerySchema>
export type DealLookupQuery = z.infer<typeof DealLookupQuerySchema>
export type ListDealTasksDueQuery = z.infer<typeof ListDealTasksDueQuerySchema>
export type CreateDealNoteRequest = z.infer<typeof CreateDealNoteRequestSchema>
export type CreateDealTaskRequest = z.infer<typeof CreateDealTaskRequestSchema>
export type TransitionItemRequest = z.infer<typeof TransitionItemRequestSchema>
export type CrmTransitionItemRequest = z.infer<typeof CrmTransitionItemRequestSchema>
export type TransitionDealStateRequest = z.infer<typeof TransitionDealStateRequestSchema>
export type ExecuteActionParams = z.infer<typeof ExecuteActionParamsSchema>
export type ExecuteActionRequest = z.infer<typeof ExecuteActionRequestSchema>
export type DealPriorityResponse = z.infer<typeof DealPrioritySchema>
export type DealListResponse = z.infer<typeof DealListResponseSchema>
export type DealSummaryResponse = z.infer<typeof DealSummaryResponseSchema>
export type DealLookupItem = z.infer<typeof DealLookupItemSchema>
export type DealLookupResponse = z.infer<typeof DealLookupResponseSchema>
export type ConversationMessage = z.infer<typeof ConversationMessageSchema>
export type DealLineageListRef = z.infer<typeof DealLineageListRefSchema>
export type DealLineageProjectRef = z.infer<typeof DealLineageProjectRefSchema>
export type DealLineageClientRef = z.infer<typeof DealLineageClientRefSchema>
export type DealLineage = z.infer<typeof DealLineageSchema>
export type DealDetailResponse = z.infer<typeof DealDetailResponseSchema>
export type DealNoteResponse = z.infer<typeof DealNoteResponseSchema>
export type DealNoteListResponse = z.infer<typeof DealNoteListResponseSchema>
export type DealTaskResponse = z.infer<typeof DealTaskResponseSchema>
export type DealTaskListResponse = z.infer<typeof DealTaskListResponseSchema>

// ---------------------------------------------------------------------------
// List Management API Schemas
//
// Request/response validation for /api/acquisition/lists surface.
// Used by both the API route handlers and the frontend hooks.
//
// Table mapping:
//   acq_lists            -> AcqListSchemas (list/detail/progress)
//   acq_list_companies   -> AcqListSchemas (add/remove company membership)
//   acq_list_contacts    -> AcqListSchemas (add/remove contact membership)
//   acq_list_executions  -> AcqListSchemas (execution history)
// ---------------------------------------------------------------------------

// ---------------------------------------------------------------------------
// Primitives — list status enum + jsonb config schemas
// ---------------------------------------------------------------------------

/**
 * Lifecycle status enum for `acq_lists.status` (mirrors DB CHECK constraint
 * from migration 20260428000003_lead_gen_acq_lists_status_and_config.sql).
 */
export const ListStatusSchema = z.enum(['draft', 'enriching', 'launched', 'closing', 'archived'])

/**
 * Scraping criteria stored in `acq_lists.scraping_config` jsonb.
 * Edited via the UI; consumed by lgn-01 prospecting workflows (Apify input shape,
 * geography, vertical, size). All fields are optional — empty config is valid.
 */
export const ScrapingConfigSchema = z.object({
  vertical: z.string().trim().max(255).optional(),
  geography: z.string().trim().max(500).optional(),
  size: z.string().trim().max(255).optional(),
  apifyInput: z.record(z.string(), z.unknown()).optional()
})

/**
 * ICP / qualification rubric stored in `acq_lists.icp` jsonb.
 * Replaces the legacy `config.qualification` blob. Consumed by the
 * company-qualification workflow.
 */
export const IcpRubricSchema = z.object({
  qualificationRubricKey: z.string().trim().max(255).nullish(),
  targetDescription: z.string().optional(),
  minReviewCount: z.number().int().min(0).optional(),
  minRating: z.number().min(0).max(5).optional(),
  excludeFranchises: z.boolean().optional(),
  customRules: z.string().optional()
})

/**
 * One stage entry in a list's `pipeline_config.stages[]`.
 *
 * Stage catalogs are model-owned. The published core schema validates the
 * transport shape and leaves closed-catalog checks to callers with a resolved
 * Organization Model.
 */
export const PipelineStageSchema = z.object({
  key: LeadGenStageKeySchema,
  label: z.string().optional(),
  enabled: z.boolean().optional(),
  order: z.number().int().optional()
})

export const DataModeSchema = z.enum(['mock', 'live'])

/**
 * Pipeline presentation contract stored in `acq_lists.pipeline_config` jsonb.
 * `stages[].key` validates against the catalog; the rest is presentation only.
 */
export const PipelineConfigSchema = z.object({
  stages: z.array(PipelineStageSchema).optional(),
  dataMode: DataModeSchema.optional()
})

export const BuildPlanSnapshotStepSchema = z
  .object({
    id: z.string().trim().min(1).max(100),
    label: z.string().trim().min(1).max(120),
    description: z.string().trim().min(1).max(2000).optional(),
    primaryEntity: z.enum(['company', 'contact']),
    outputs: z.array(z.enum(['company', 'contact', 'export'])).min(1),
    stageKey: LeadGenStageKeySchema,
    recordEntity: z.enum(['company', 'contact']).optional(),
    recordsStageKey: LeadGenStageKeySchema.optional(),
    recordSourceStageKey: LeadGenStageKeySchema.optional(),
    dependsOn: z.array(z.string().trim().min(1).max(100)).optional(),
    dependencyMode: z.literal('per-record-eligibility'),
    actionKey: LeadGenActionKeySchema,
    defaultBatchSize: z.number().int().positive(),
    maxBatchSize: z.number().int().positive(),
    recordColumns: z
      .object({
        company: z.array(RecordColumnConfigSchema).optional(),
        contact: z.array(RecordColumnConfigSchema).optional()
      })
      .optional(),
    credentialRequirements: z.array(CredentialRequirementSchema).optional()
  })
  .refine((step) => step.defaultBatchSize <= step.maxBatchSize, {
    message: 'defaultBatchSize must be less than or equal to maxBatchSize',
    path: ['defaultBatchSize']
  })

export const BuildPlanSnapshotSchema = z
  .object({
    templateId: z.string().trim().min(1).max(100),
    templateLabel: z.string().trim().min(1).max(120),
    steps: z.array(BuildPlanSnapshotStepSchema).min(1)
  })
  .superRefine((snapshot, ctx) => {
    const stepIds = new Set<string>()

    snapshot.steps.forEach((step, index) => {
      if (stepIds.has(step.id)) {
        ctx.addIssue({
          code: z.ZodIssueCode.custom,
          message: `duplicate build-plan step id "${step.id}"`,
          path: ['steps', index, 'id']
        })
      }
      stepIds.add(step.id)
    })

    snapshot.steps.forEach((step, index) => {
      for (const dependencyId of step.dependsOn ?? []) {
        if (!stepIds.has(dependencyId)) {
          ctx.addIssue({
            code: z.ZodIssueCode.custom,
            message: `dependsOn references unknown build-plan step "${dependencyId}"`,
            path: ['steps', index, 'dependsOn']
          })
        }
      }
    })
  })

export const AcqListMetadataSchema = z
  .object({
    buildPlanSnapshot: BuildPlanSnapshotSchema.optional()
  })
  .catchall(z.unknown())

// Build-template IDs are tenant-owned OM catalog entries. Published core only
// validates the transport shape; API/services validate membership against the
// tenant's resolved Organization Model before creating or changing snapshots.
export const ProspectingBuildTemplateIdSchema = z.string().trim().min(1).max(100)

// ---------------------------------------------------------------------------
// List telemetry / progress schemas
// ---------------------------------------------------------------------------

export const ListStageCountsSchema = z.object({
  // Attempted counts by canonical lead-gen stage. The detailed status
  // distribution lives on ListProgress; telemetry keeps the overview payload small.
  stageCounts: z.object({
    populated: z.number().int(),
    extracted: z.number().int(),
    qualified: z.number().int(),
    discovered: z.number().int(),
    verified: z.number().int(),
    personalized: z.number().int(),
    uploaded: z.number().int()
  }),
  deliverability: z.object({
    valid: z.number().int(),
    risky: z.number().int(),
    invalid: z.number().int(),
    unknown: z.number().int(),
    bounced: z.number().int()
  })
})

export const ListTelemetrySchema = z.object({
  listId: UuidSchema,
  totalCompanies: z.number().int(),
  totalContacts: z.number().int(),
  stageCounts: ListStageCountsSchema.shape.stageCounts,
  deliverability: ListStageCountsSchema.shape.deliverability,
  activeWorkflows: z.array(z.string()).optional()
})

// ---------------------------------------------------------------------------
// Params
// ---------------------------------------------------------------------------

export const ListIdParamsSchema = z.object({
  listId: UuidSchema
})

// ---------------------------------------------------------------------------
// Request body schemas (all use .strict() — rejects unknown fields)
// ---------------------------------------------------------------------------

export const CreateListRequestSchema = z
  .object({
    name: z.string().trim().min(1).max(255),
    description: z.string().trim().nullable().optional(),
    status: ListStatusSchema.optional(),
    buildTemplateId: ProspectingBuildTemplateIdSchema.optional(),
    scrapingConfig: ScrapingConfigSchema.optional(),
    icp: IcpRubricSchema.optional(),
    pipelineConfig: PipelineConfigSchema.optional()
  })
  .strict()

export const UpdateListRequestSchema = z
  .object({
    name: z.string().trim().min(1).max(255).optional(),
    description: z.string().trim().nullable().optional(),
    batchIds: z.array(z.string()).optional(),
    buildTemplateId: ProspectingBuildTemplateIdSchema.optional(),
    confirmBuildTemplateChange: z.literal(true).optional()
  })
  .strict()
  .refine(
    (data) =>
      data.name !== undefined ||
      data.description !== undefined ||
      data.batchIds !== undefined ||
      data.buildTemplateId !== undefined,
    {
      message: 'At least one field (name, description, batchIds, or buildTemplateId) must be provided'
    }
  )
  .refine((data) => data.buildTemplateId === undefined || data.confirmBuildTemplateChange === true, {
    message: 'confirmBuildTemplateChange must be true when changing buildTemplateId',
    path: ['confirmBuildTemplateChange']
  })

/**
 * Status-only PATCH body for `/acquisition/lists/:listId/status`.
 * Replaces the previous `transitionList` flow.
 */
export const UpdateListStatusRequestSchema = z
  .object({
    status: ListStatusSchema
  })
  .strict()

/**
 * Partial patch for the three jsonb config columns. UI sends only the edited
 * subtree; server writes the field as-is (no deep merge — each column is
 * replaced atomically when present in the patch).
 */
export const UpdateListConfigRequestSchema = z
  .object({
    scrapingConfig: ScrapingConfigSchema.partial().optional(),
    icp: IcpRubricSchema.partial().optional(),
    pipelineConfig: PipelineConfigSchema.partial().optional()
  })
  .strict()
  .refine((data) => data.scrapingConfig !== undefined || data.icp !== undefined || data.pipelineConfig !== undefined, {
    message: 'At least one of scrapingConfig, icp, or pipelineConfig must be provided'
  })

export const AddCompaniesToListRequestSchema = z
  .object({
    companyIds: z.array(UuidSchema).min(1).max(1000)
  })
  .strict()

export const RemoveCompaniesFromListRequestSchema = z
  .object({
    companyIds: z.array(UuidSchema).min(1).max(1000)
  })
  .strict()

export const AddContactsToListRequestSchema = z
  .object({
    contactIds: z.array(UuidSchema).min(1).max(1000)
  })
  .strict()

export const RecordListExecutionRequestSchema = z
  .object({
    executionId: UuidSchema,
    configSnapshot: z.record(z.string(), z.unknown()).optional()
  })
  .strict()

// ---------------------------------------------------------------------------
// Response schemas (no .strict() — allows forward-compatible additions)
// ---------------------------------------------------------------------------

/**
 * Single list as returned by /api/acquisition/lists/:id etc.
 * Camel-cased domain shape matching AcqList in types.ts.
 */
export const AcqListResponseSchema = z.object({
  id: z.string(),
  organizationId: z.string(),
  name: z.string(),
  description: z.string().nullable(),
  batchIds: z.array(z.string()),
  instantlyCampaignId: z.string().nullable(),
  /** Lifecycle status (draft | enriching | launched | closing | archived). */
  status: ListStatusSchema,
  metadata: AcqListMetadataSchema,
  launchedAt: z.string().nullable(),
  completedAt: z.string().nullable(),
  createdAt: z.string(),
  /** Scraping criteria stored as jsonb on the row. */
  scrapingConfig: ScrapingConfigSchema,
  /** ICP / qualification rubric stored as jsonb on the row. */
  icp: IcpRubricSchema,
  /** Pipeline presentation contract stored as jsonb on the row. */
  pipelineConfig: PipelineConfigSchema
})

export const AcqListListResponseSchema = z.array(AcqListResponseSchema)

export const ListTelemetryResponseSchema = ListTelemetrySchema

export const ListTelemetryListResponseSchema = z.array(ListTelemetrySchema)

const QueryBooleanSchema = z.preprocess((value) => {
  if (value === 'true' || value === '1' || value === true) return true
  if (value === 'false' || value === '0' || value === false) return false
  return value
}, z.boolean())

export const ListReadQuerySchema = z
  .object({
    status: ListStatusSchema.optional(),
    batch: z.string().trim().min(1).max(255).optional(),
    vertical: z.string().trim().min(1).max(255).optional(),
    limit: z.coerce.number().int().min(1).max(500).optional(),
    offset: z.coerce.number().int().min(0).optional()
  })
  .strict()

export const GetListQuerySchema = z
  .object({
    includeDeals: QueryBooleanSchema.default(true),
    includeProgress: QueryBooleanSchema.default(false),
    dealLimit: z.coerce.number().int().min(0).max(100).default(25)
  })
  .strict()

/**
 * Per-stage progress aggregate for a single pipeline stage.
 * `attempted` counts terminal statuses, including success, no-result, skipped,
 * error, and tolerant-reader `other` values.
 * `total` = total member/company count for the list.
 */
export const ListStageProgressSchema = z.object({
  total: z.number().int().min(0),
  attempted: z.number().int().min(0),
  success: z.number().int().min(0),
  noResult: z.number().int().min(0),
  skipped: z.number().int().min(0),
  error: z.number().int().min(0),
  other: z.number().int().min(0),
  notAttempted: z.number().int().min(0)
})

/**
 * Progress response for GET /acquisition/lists/:listId/progress.
 * Aggregated on-demand from processing_state status values.
 * Stage keys are discovered from observed processing_state keys.
 */
export const ListProgressResponseSchema = z.object({
  totalMembers: z.number().int().min(0),
  totalCompanies: z.number().int().min(0),
  byCompanyStage: z.record(z.string(), ListStageProgressSchema),
  byContactStage: z.record(z.string(), ListStageProgressSchema)
})

export const AcqListDealRefSchema = z.object({
  id: z.string(),
  contactEmail: z.string(),
  stageKey: z.string().nullable(),
  stateKey: z.string().nullable(),
  sourceType: z.string().nullable(),
  lastActivityAt: z.string()
})

export const AcqListLineageSchema = z.object({
  deals: z.object({
    total: z.number().int().min(0),
    refs: z.array(AcqListDealRefSchema),
    truncated: z.boolean()
  })
})

export const AcqListDetailResponseSchema = AcqListResponseSchema.extend({
  lineage: AcqListLineageSchema.optional(),
  progress: ListProgressResponseSchema.optional()
})

export const AcqListStatusListItemSchema = z.object({
  listId: z.string(),
  name: z.string(),
  status: ListStatusSchema,
  totalCompanies: z.number().int().min(0),
  totalContacts: z.number().int().min(0),
  totalDeals: z.number().int().min(0),
  createdAt: z.string()
})

export const AcqListStatusResponseSchema = z.object({
  totalLists: z.number().int().min(0),
  totalCompanies: z.number().int().min(0),
  totalContacts: z.number().int().min(0),
  totalDeals: z.number().int().min(0),
  byStatus: z.record(z.string(), z.number().int().min(0)),
  lists: z.array(AcqListStatusListItemSchema)
})

/**
 * Row from acq_list_executions joined with the execution summary,
 * shaped for the /lists/:id/executions response.
 */
export const ListExecutionSummarySchema = z.object({
  executionId: z.string(),
  resourceId: z.string(),
  status: z.string(),
  createdAt: z.string(),
  completedAt: z.string().nullable(),
  durationMs: z.number().int().nullable(),
  input: z.unknown().nullable().optional()
})

export const ListExecutionsResponseSchema = z.array(ListExecutionSummarySchema)

// ---------------------------------------------------------------------------
// Company / Contact API Schemas
// ---------------------------------------------------------------------------

export const AcqCompanyStatusSchema = z.enum(['active', 'invalid'])
export const AcqContactStatusSchema = z.enum(['active', 'invalid'])
export const AcqEmailValidSchema = z.enum(['VALID', 'INVALID', 'RISKY', 'UNKNOWN'])

export const CompanyIdParamsSchema = z.object({
  companyId: UuidSchema
})

export const ContactIdParamsSchema = z.object({
  contactId: UuidSchema
})

export const ListCompaniesQuerySchema = z
  .object({
    search: z.string().trim().min(1).max(200).optional(),
    listId: UuidSchema.optional(),
    domain: z.string().trim().min(1).max(255).optional(),
    website: z.string().trim().min(1).max(2048).optional(),
    segment: z.string().trim().min(1).max(255).optional(),
    category: z.string().trim().min(1).max(255).optional(),
    pipelineStatus: z.unknown().optional(),
    batchId: z.string().trim().min(1).max(255).optional(),
    status: AcqCompanyStatusSchema.optional(),
    includeAll: QueryBooleanSchema.optional(),
    limit: z.coerce.number().int().min(1).max(5000).default(50),
    offset: z.coerce.number().int().min(0).default(0)
  })
  .strict()

export const ListContactsQuerySchema = z
  .object({
    search: z.string().trim().min(1).max(200).optional(),
    listId: UuidSchema.optional(),
    openingLineIsNull: QueryBooleanSchema.optional(),
    batchId: z.string().trim().min(1).max(255).optional(),
    contactStatus: AcqContactStatusSchema.optional(),
    limit: z.coerce.number().int().min(1).max(5000).default(5000),
    offset: z.coerce.number().int().min(0).default(0)
  })
  .strict()

export const CreateCompanyRequestSchema = z
  .object({
    name: z.string().trim().min(1).max(255),
    clientId: UuidSchema.nullable().optional(),
    domain: z.string().trim().min(1).max(255).optional(),
    linkedinUrl: z.string().trim().url().optional(),
    website: z.string().trim().url().optional(),
    numEmployees: z.number().int().min(0).optional(),
    foundedYear: z.number().int().optional(),
    locationCity: z.string().trim().min(1).max(255).optional(),
    locationState: z.string().trim().min(1).max(255).optional(),
    category: z.string().trim().min(1).max(255).optional(),
    source: z.string().trim().min(1).max(255).optional(),
    batchId: z.string().trim().min(1).max(255).optional(),
    pipelineStatus: z.unknown().optional(),
    verticalResearch: z.string().trim().min(1).max(5000).optional()
  })
  .strict()

export const UpdateCompanyRequestSchema = z
  .object({
    name: z.string().trim().min(1).max(255).optional(),
    clientId: UuidSchema.nullable().optional(),
    domain: z.string().trim().min(1).max(255).optional(),
    linkedinUrl: z.string().trim().url().optional(),
    website: z.string().trim().url().optional(),
    numEmployees: z.number().int().min(0).optional(),
    foundedYear: z.number().int().optional(),
    locationCity: z.string().trim().min(1).max(255).optional(),
    locationState: z.string().trim().min(1).max(255).optional(),
    category: z.string().trim().min(1).max(255).optional(),
    segment: z.string().trim().min(1).max(255).optional(),
    processingState: CompanyProcessingStateSchema.optional(),
    pipelineStatus: z.unknown().optional(),
    enrichmentData: z.record(z.string(), z.unknown()).optional(),
    source: z.string().trim().min(1).max(255).optional(),
    batchId: z.string().trim().min(1).max(255).optional(),
    status: AcqCompanyStatusSchema.optional(),
    verticalResearch: z.string().trim().min(1).max(5000).nullable().optional()
  })
  .strict()
  .refine(
    (data) =>
      data.name !== undefined ||
      data.clientId !== undefined ||
      data.domain !== undefined ||
      data.linkedinUrl !== undefined ||
      data.website !== undefined ||
      data.numEmployees !== undefined ||
      data.foundedYear !== undefined ||
      data.locationCity !== undefined ||
      data.locationState !== undefined ||
      data.category !== undefined ||
      data.segment !== undefined ||
      data.processingState !== undefined ||
      data.pipelineStatus !== undefined ||
      data.enrichmentData !== undefined ||
      data.source !== undefined ||
      data.batchId !== undefined ||
      data.status !== undefined ||
      data.verticalResearch !== undefined,
    {
      message: 'At least one field must be provided'
    }
  )

export const CreateContactRequestSchema = z
  .object({
    email: z.string().trim().email(),
    clientId: UuidSchema.nullable().optional(),
    companyId: UuidSchema.optional(),
    firstName: z.string().trim().min(1).max(255).optional(),
    lastName: z.string().trim().min(1).max(255).optional(),
    linkedinUrl: z.string().trim().url().optional(),
    title: z.string().trim().min(1).max(255).optional(),
    source: z.string().trim().min(1).max(255).optional(),
    sourceId: z.string().trim().min(1).max(255).optional(),
    batchId: z.string().trim().min(1).max(255).optional(),
    pipelineStatus: z.unknown().optional()
  })
  .strict()

export const UpdateContactRequestSchema = z
  .object({
    companyId: UuidSchema.optional(),
    clientId: UuidSchema.nullable().optional(),
    emailValid: AcqEmailValidSchema.optional(),
    firstName: z.string().trim().min(1).max(255).optional(),
    lastName: z.string().trim().min(1).max(255).optional(),
    linkedinUrl: z.string().trim().url().optional(),
    title: z.string().trim().min(1).max(255).optional(),
    headline: z.string().trim().min(1).max(5000).optional(),
    filterReason: z.string().trim().min(1).max(5000).optional(),
    openingLine: z.string().trim().min(1).max(5000).optional(),
    processingState: ContactProcessingStateSchema.optional(),
    pipelineStatus: z.unknown().optional(),
    enrichmentData: z.record(z.string(), z.unknown()).optional(),
    status: AcqContactStatusSchema.optional()
  })
  .strict()
  .refine(
    (data) =>
      data.companyId !== undefined ||
      data.clientId !== undefined ||
      data.emailValid !== undefined ||
      data.firstName !== undefined ||
      data.lastName !== undefined ||
      data.linkedinUrl !== undefined ||
      data.title !== undefined ||
      data.headline !== undefined ||
      data.filterReason !== undefined ||
      data.openingLine !== undefined ||
      data.processingState !== undefined ||
      data.pipelineStatus !== undefined ||
      data.enrichmentData !== undefined ||
      data.status !== undefined,
    {
      message: 'At least one field must be provided'
    }
  )

export const AcqCompanyResponseSchema = z.object({
  id: z.string(),
  organizationId: z.string(),
  clientId: z.string().nullable().optional(),
  name: z.string(),
  domain: z.string().nullable(),
  linkedinUrl: z.string().nullable(),
  website: z.string().nullable(),
  numEmployees: z.number().nullable(),
  foundedYear: z.number().nullable(),
  locationCity: z.string().nullable(),
  locationState: z.string().nullable(),
  category: z.string().nullable(),
  categoryPain: z.string().nullable(),
  segment: z.string().nullable(),
  processingState: CompanyProcessingStateSchema.nullable(),
  pipelineStatus: z.unknown().nullable().optional(),
  enrichmentData: z.record(z.string(), z.unknown()).nullable(),
  source: z.string().nullable(),
  batchId: z.string().nullable(),
  status: AcqCompanyStatusSchema,
  contactCount: z.number().int().min(0),
  verticalResearch: z.string().nullable(),
  createdAt: z.string(),
  updatedAt: z.string()
})

export const AcqCompanyListResponseSchema = z.object({
  data: z.array(AcqCompanyResponseSchema),
  total: z.number().int(),
  limit: z.number().int(),
  offset: z.number().int()
})

export const AcqCompanyFacetsResponseSchema = z.object({
  segments: z.array(z.string()),
  categories: z.array(z.string()),
  statuses: z.array(AcqCompanyStatusSchema)
})

export const AcqContactCompanySummarySchema = z.object({
  id: z.string(),
  name: z.string(),
  domain: z.string().nullable(),
  website: z.string().nullable(),
  linkedinUrl: z.string().nullable(),
  segment: z.string().nullable(),
  category: z.string().nullable(),
  status: AcqCompanyStatusSchema
})

export const AcqContactResponseSchema = z.object({
  id: z.string(),
  organizationId: z.string(),
  clientId: z.string().nullable().optional(),
  companyId: z.string().nullable(),
  email: z.string(),
  emailValid: AcqEmailValidSchema.nullable(),
  firstName: z.string().nullable(),
  lastName: z.string().nullable(),
  linkedinUrl: z.string().nullable(),
  title: z.string().nullable(),
  headline: z.string().nullable(),
  filterReason: z.string().nullable(),
  openingLine: z.string().nullable(),
  source: z.string().nullable(),
  sourceId: z.string().nullable(),
  processingState: ContactProcessingStateSchema.nullable(),
  pipelineStatus: z.unknown().nullable().optional(),
  enrichmentData: z.record(z.string(), z.unknown()).nullable(),
  attioPersonId: z.string().nullable(),
  batchId: z.string().nullable(),
  status: AcqContactStatusSchema,
  company: AcqContactCompanySummarySchema.nullable().optional(),
  createdAt: z.string(),
  updatedAt: z.string()
})

export const AcqContactListResponseSchema = z.object({
  data: z.array(AcqContactResponseSchema),
  total: z.number().int(),
  limit: z.number().int(),
  offset: z.number().int()
})

// ---------------------------------------------------------------------------
// Track A: Artifacts API Schemas
// ---------------------------------------------------------------------------

export const AcqArtifactOwnerKindSchema = z.enum(['company', 'contact', 'deal', 'list', 'list_member'])

export const ListArtifactsQuerySchema = z
  .object({
    ownerKind: AcqArtifactOwnerKindSchema,
    ownerId: UuidSchema
  })
  .strict()

export const CreateArtifactRequestSchema = z
  .object({
    ownerKind: AcqArtifactOwnerKindSchema,
    ownerId: UuidSchema,
    kind: z.string().trim().min(1).max(255),
    content: z.record(z.string(), z.unknown()),
    sourceExecutionId: UuidSchema.optional()
  })
  .strict()

export const AcqArtifactResponseSchema = z.object({
  id: z.string(),
  organizationId: z.string(),
  ownerKind: z.string(),
  ownerId: z.string(),
  kind: z.string(),
  content: z.record(z.string(), z.unknown()),
  sourceExecutionId: z.string().nullable(),
  createdBy: z.string().nullable(),
  createdAt: z.string(),
  version: z.number().int()
})

export const AcqArtifactListResponseSchema = z.object({
  artifacts: z.array(AcqArtifactResponseSchema)
})

// ---------------------------------------------------------------------------
// Track B: List Members API Schemas
// ---------------------------------------------------------------------------

export const ListMembersQuerySchema = z
  .object({
    limit: z.coerce.number().int().min(1).max(500).default(50),
    offset: z.coerce.number().int().min(0).default(0)
  })
  .strict()

export const ListRecordEntitySchema = z.enum(['company', 'contact'])

export const ListRecordsQuerySchema = z
  .object({
    entity: ListRecordEntitySchema,
    stage: LeadGenStageKeySchema.optional(),
    limit: z.coerce.number().int().min(1).max(500).default(50),
    offset: z.coerce.number().int().min(0).default(0)
  })
  .strict()

export const MemberIdParamsSchema = z.object({
  memberId: UuidSchema
})

export const AcqListMemberContactSummarySchema = z.object({
  id: z.string(),
  email: z.string(),
  firstName: z.string().nullable(),
  lastName: z.string().nullable(),
  title: z.string().nullable(),
  linkedinUrl: z.string().nullable(),
  companyId: z.string().nullable()
})

export const AcqListMemberResponseSchema = z.object({
  id: z.string(),
  listId: z.string(),
  contactId: z.string(),
  pipelineKey: z.string(),
  stageKey: z.string(),
  stateKey: z.string(),
  activityLog: z.unknown(),
  addedAt: z.string(),
  addedBy: z.string().nullable(),
  sourceExecutionId: z.string().nullable(),
  contact: AcqListMemberContactSummarySchema.nullable()
})

export const AcqListMembersResponseSchema = z.object({
  members: z.array(AcqListMemberResponseSchema)
})

export const AcqListRecordCompanySummarySchema = z.object({
  id: z.string(),
  name: z.string(),
  domain: z.string().nullable(),
  website: z.string().nullable(),
  linkedinUrl: z.string().nullable(),
  numEmployees: z.number().nullable(),
  foundedYear: z.number().nullable(),
  locationCity: z.string().nullable(),
  locationState: z.string().nullable(),
  category: z.string().nullable(),
  segment: z.string().nullable(),
  status: AcqCompanyStatusSchema,
  qualificationScore: z.number().nullable(),
  qualificationSignals: z.record(z.string(), z.unknown()).nullable(),
  qualificationRubricKey: z.string().nullable()
})

export const AcqListRecordContactSummarySchema = z.object({
  id: z.string(),
  email: z.string(),
  firstName: z.string().nullable(),
  lastName: z.string().nullable(),
  title: z.string().nullable(),
  headline: z.string().nullable(),
  linkedinUrl: z.string().nullable(),
  companyId: z.string().nullable(),
  status: AcqContactStatusSchema,
  qualificationScore: z.number().nullable(),
  qualificationSignals: z.record(z.string(), z.unknown()).nullable(),
  qualificationRubricKey: z.string().nullable()
})

const ListRecordBaseSchema = z.object({
  id: z.string(),
  listId: z.string(),
  pipelineKey: z.string(),
  stageKey: z.string(),
  stateKey: z.string(),
  activityLog: z.unknown(),
  addedAt: z.string(),
  addedBy: z.string().nullable(),
  sourceExecutionId: z.string().nullable(),
  processingState: z.record(z.string(), z.unknown()).nullable(),
  enrichmentData: z.record(z.string(), z.unknown()).nullable()
})

export const AcqListCompanyRecordRowSchema = ListRecordBaseSchema.extend({
  entity: z.literal('company'),
  companyId: z.string(),
  company: AcqListRecordCompanySummarySchema.nullable()
})

export const AcqListContactRecordRowSchema = ListRecordBaseSchema.extend({
  entity: z.literal('contact'),
  contactId: z.string(),
  contact: AcqListRecordContactSummarySchema.nullable()
})

export const ListRecordRowSchema = z.discriminatedUnion('entity', [
  AcqListCompanyRecordRowSchema,
  AcqListContactRecordRowSchema
])

export const ListRecordsResponseSchema = z.object({
  data: z.array(ListRecordRowSchema),
  total: z.number().int().min(0),
  limit: z.number().int().min(1),
  offset: z.number().int().min(0)
})

// ---------------------------------------------------------------------------
// Track B: List Companies API Schemas
// ---------------------------------------------------------------------------

export const ListCompanyIdParamsSchema = z.object({
  listCompanyId: UuidSchema
})

export const AcqListCompanyResponseSchema = z.object({
  id: z.string(),
  listId: z.string(),
  companyId: z.string(),
  pipelineKey: z.string(),
  stageKey: z.string(),
  stateKey: z.string(),
  activityLog: z.unknown(),
  addedAt: z.string(),
  addedBy: z.string().nullable(),
  sourceExecutionId: z.string().nullable()
})

// ---------------------------------------------------------------------------
// Track B: Transition request for list, list-member, and list-company substrate routes.
// CRM deals use DealSchemas.TransitionItemRequest, which is catalog-backed.
// ---------------------------------------------------------------------------

export const AcqCompanySchemas = {
  CompanyProcessingState: CompanyProcessingStateSchema,
  CompanyIdParams: CompanyIdParamsSchema,
  ListCompaniesQuery: ListCompaniesQuerySchema,
  CreateCompanyRequest: CreateCompanyRequestSchema,
  UpdateCompanyRequest: UpdateCompanyRequestSchema,
  AcqCompanyResponse: AcqCompanyResponseSchema,
  AcqCompanyListResponse: AcqCompanyListResponseSchema,
  AcqCompanyFacetsResponse: AcqCompanyFacetsResponseSchema
}

export const AcqContactSchemas = {
  ContactProcessingState: ContactProcessingStateSchema,
  ContactIdParams: ContactIdParamsSchema,
  ListContactsQuery: ListContactsQuerySchema,
  CreateContactRequest: CreateContactRequestSchema,
  UpdateContactRequest: UpdateContactRequestSchema,
  AcqContactResponse: AcqContactResponseSchema,
  AcqContactListResponse: AcqContactListResponseSchema
}

export type AcqCompanyStatus = z.infer<typeof AcqCompanyStatusSchema>
export type AcqContactStatus = z.infer<typeof AcqContactStatusSchema>
export type AcqEmailValid = z.infer<typeof AcqEmailValidSchema>
export type CompanyIdParams = z.infer<typeof CompanyIdParamsSchema>
export type ContactIdParams = z.infer<typeof ContactIdParamsSchema>
export type ListCompaniesQuery = z.infer<typeof ListCompaniesQuerySchema>
export type ListContactsQuery = z.infer<typeof ListContactsQuerySchema>
export type CreateCompanyRequest = z.infer<typeof CreateCompanyRequestSchema>
export type UpdateCompanyRequest = z.infer<typeof UpdateCompanyRequestSchema>
export type CreateContactRequest = z.infer<typeof CreateContactRequestSchema>
export type UpdateContactRequest = z.infer<typeof UpdateContactRequestSchema>
export type AcqCompanyResponse = z.infer<typeof AcqCompanyResponseSchema>
export type AcqCompanyListResponse = z.infer<typeof AcqCompanyListResponseSchema>
export type AcqCompanyFacetsResponse = z.infer<typeof AcqCompanyFacetsResponseSchema>
export type AcqContactCompanySummary = z.infer<typeof AcqContactCompanySummarySchema>
export type AcqContactResponse = z.infer<typeof AcqContactResponseSchema>
export type AcqContactListResponse = z.infer<typeof AcqContactListResponseSchema>

// ---------------------------------------------------------------------------
// Bundled export
// ---------------------------------------------------------------------------

export const AcqListSchemas = {
  // Params
  ListIdParams: ListIdParamsSchema,

  // Primitives (for UI / tests)
  ListStatus: ListStatusSchema,
  ScrapingConfig: ScrapingConfigSchema,
  IcpRubric: IcpRubricSchema,
  PipelineConfig: PipelineConfigSchema,
  DataMode: DataModeSchema,
  PipelineStage: PipelineStageSchema,
  BuildPlanSnapshot: BuildPlanSnapshotSchema,
  BuildPlanSnapshotStep: BuildPlanSnapshotStepSchema,
  AcqListMetadata: AcqListMetadataSchema,
  LeadGenStageKey: LeadGenStageKeySchema,
  LeadGenActionKey: LeadGenActionKeySchema,
  ProcessingStageStatus: ProcessingStageStatusSchema,
  ProcessingState: ProcessingStateSchema,
  ListStageCounts: ListStageCountsSchema,
  ListTelemetry: ListTelemetrySchema,

  // Requests
  ListReadQuery: ListReadQuerySchema,
  GetListQuery: GetListQuerySchema,
  CreateListRequest: CreateListRequestSchema,
  UpdateListRequest: UpdateListRequestSchema,
  UpdateListStatusRequest: UpdateListStatusRequestSchema,
  UpdateListConfigRequest: UpdateListConfigRequestSchema,
  AddCompaniesToListRequest: AddCompaniesToListRequestSchema,
  RemoveCompaniesFromListRequest: RemoveCompaniesFromListRequestSchema,
  AddContactsToListRequest: AddContactsToListRequestSchema,
  RecordListExecutionRequest: RecordListExecutionRequestSchema,

  // Responses
  AcqListResponse: AcqListResponseSchema,
  AcqListDetailResponse: AcqListDetailResponseSchema,
  AcqListListResponse: AcqListListResponseSchema,
  AcqListDealRef: AcqListDealRefSchema,
  AcqListLineage: AcqListLineageSchema,
  AcqListStatusResponse: AcqListStatusResponseSchema,
  ListTelemetryResponse: ListTelemetryResponseSchema,
  ListTelemetryListResponse: ListTelemetryListResponseSchema,
  ListExecutionsResponse: ListExecutionsResponseSchema,
  ListProgressResponse: ListProgressResponseSchema
}

// ---------------------------------------------------------------------------
// Track A/B bundled schemas
// ---------------------------------------------------------------------------

export const AcqSubstrateSchemas = {
  // Artifacts
  ListArtifactsQuery: ListArtifactsQuerySchema,
  CreateArtifactRequest: CreateArtifactRequestSchema,
  AcqArtifactResponse: AcqArtifactResponseSchema,
  AcqArtifactListResponse: AcqArtifactListResponseSchema,

  // List members
  ListMembersQuery: ListMembersQuerySchema,
  ListRecordsQuery: ListRecordsQuerySchema,
  MemberIdParams: MemberIdParamsSchema,
  AcqListMemberResponse: AcqListMemberResponseSchema,
  AcqListMembersResponse: AcqListMembersResponseSchema,
  AcqListCompanyRecordRow: AcqListCompanyRecordRowSchema,
  AcqListContactRecordRow: AcqListContactRecordRowSchema,
  ListRecordRow: ListRecordRowSchema,
  ListRecordsResponse: ListRecordsResponseSchema,

  // List companies
  ListCompanyIdParams: ListCompanyIdParamsSchema,
  AcqListCompanyResponse: AcqListCompanyResponseSchema,

  // Transition (generic stateful substrate)
  TransitionItemRequest: TransitionItemRequestSchema
}

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

// ---------------------------------------------------------------------------
// Inferred types — Track A/B substrate
// ---------------------------------------------------------------------------

export type AcqArtifactOwnerKind = z.infer<typeof AcqArtifactOwnerKindSchema>
export type ListArtifactsQuery = z.infer<typeof ListArtifactsQuerySchema>
export type CreateArtifactRequest = z.infer<typeof CreateArtifactRequestSchema>
export type AcqArtifactResponse = z.infer<typeof AcqArtifactResponseSchema>
export type AcqArtifactListResponse = z.infer<typeof AcqArtifactListResponseSchema>
export type ListMembersQuery = z.infer<typeof ListMembersQuerySchema>
export type ListRecordEntity = z.infer<typeof ListRecordEntitySchema>
export type ListRecordsQuery = z.infer<typeof ListRecordsQuerySchema>
export type MemberIdParams = z.infer<typeof MemberIdParamsSchema>
export type AcqListMemberContactSummary = z.infer<typeof AcqListMemberContactSummarySchema>
export type AcqListMemberResponse = z.infer<typeof AcqListMemberResponseSchema>
export type AcqListMembersResponse = z.infer<typeof AcqListMembersResponseSchema>
export type AcqListCompanyRecordRow = z.infer<typeof AcqListCompanyRecordRowSchema>
export type AcqListContactRecordRow = z.infer<typeof AcqListContactRecordRowSchema>
export type ListRecordRow = z.infer<typeof ListRecordRowSchema>
export type ListRecordsResponse = z.infer<typeof ListRecordsResponseSchema>
export type ListCompanyIdParams = z.infer<typeof ListCompanyIdParamsSchema>
export type AcqListCompanyResponse = z.infer<typeof AcqListCompanyResponseSchema>

// ---------------------------------------------------------------------------

export type ListStatus = z.infer<typeof ListStatusSchema>
export type ScrapingConfig = z.infer<typeof ScrapingConfigSchema>
export type IcpRubric = z.infer<typeof IcpRubricSchema>
export type PipelineStage = z.infer<typeof PipelineStageSchema>
export type DataMode = z.infer<typeof DataModeSchema>
export type PipelineConfig = z.infer<typeof PipelineConfigSchema>
export type BuildPlanSnapshotStep = z.infer<typeof BuildPlanSnapshotStepSchema>
export type BuildPlanSnapshot = z.infer<typeof BuildPlanSnapshotSchema>
export type AcqListMetadata = z.infer<typeof AcqListMetadataSchema>
export type LeadGenActionKey = z.infer<typeof LeadGenActionKeySchema>
export type ProcessingStageStatus = z.infer<typeof ProcessingStageStatusSchema>
export type ListStageCountsInput = z.infer<typeof ListStageCountsSchema>['stageCounts']
export type ListTelemetryInput = z.infer<typeof ListTelemetrySchema>
export type ListIdParams = z.infer<typeof ListIdParamsSchema>
export type ListReadQuery = z.infer<typeof ListReadQuerySchema>
export type GetListQuery = z.infer<typeof GetListQuerySchema>
export type CreateListRequest = z.infer<typeof CreateListRequestSchema>
export type UpdateListRequest = z.infer<typeof UpdateListRequestSchema>
export type UpdateListStatusRequest = z.infer<typeof UpdateListStatusRequestSchema>
export type UpdateListConfigRequest = z.infer<typeof UpdateListConfigRequestSchema>
export type AddCompaniesToListRequest = z.infer<typeof AddCompaniesToListRequestSchema>
export type RemoveCompaniesFromListRequest = z.infer<typeof RemoveCompaniesFromListRequestSchema>
export type AddContactsToListRequest = z.infer<typeof AddContactsToListRequestSchema>
export type RecordListExecutionRequest = z.infer<typeof RecordListExecutionRequestSchema>
export type AcqListResponse = z.infer<typeof AcqListResponseSchema>
export type AcqListDetailResponse = z.infer<typeof AcqListDetailResponseSchema>
export type AcqListListResponse = z.infer<typeof AcqListListResponseSchema>
export type AcqListDealRef = z.infer<typeof AcqListDealRefSchema>
export type AcqListLineage = z.infer<typeof AcqListLineageSchema>
export type AcqListStatusResponse = z.infer<typeof AcqListStatusResponseSchema>
export type ListTelemetryResponse = z.infer<typeof ListTelemetryResponseSchema>
export type ListTelemetryListResponse = z.infer<typeof ListTelemetryListResponseSchema>
export type ListExecutionSummaryInput = z.infer<typeof ListExecutionSummarySchema>
export type ListExecutionsResponse = z.infer<typeof ListExecutionsResponseSchema>
export type ListStageProgress = z.infer<typeof ListStageProgressSchema>
export type ListProgress = z.infer<typeof ListProgressResponseSchema>
