import {
  pgTable,
  pgEnum,
  uuid,
  text,
  integer,
  boolean,
  numeric,
  timestamp,
  jsonb,
  index,
  doublePrecision,
  uniqueIndex,
  check,
  type AnyPgColumn,
} from 'drizzle-orm/pg-core';
import { sql } from 'drizzle-orm';

// Estado comercial del lead — RF-D-03. Lo que el reformista gestiona a mano.
export const leadEstado = pgEnum('lead_estado', [
  'nuevo',
  'contactado',
  'visita_agendada',
  'presupuesto_enviado',
  'ganado',
  'perdido',
]);

// Avance técnico en el funnel B2C (docs/funnel.md, superficie C).
// Cada valor = un momento del pipeline; el "siguiente paso" se deriva de aquí.
export const pipelineStage = pgEnum('pipeline_stage', [
  'form_completado', // 2. dejó nombre+tel+email+opt-in
  'fotos_subidas', // 3. subió 2-4 fotos
  'prellamada_enviada', // 4. SMS + WhatsApp pre-llamada
  'llamada_completada', // 5. agente IA terminó la cualificación
  'render_generado', // 6. Nano Banana generó el render
  'presupuesto_generado', // 6. motor de presupuesto + PDF listos
  'whatsapp_entregado', // 7. entregado al cliente + lead caliente al panel
]);

export const tipoReforma = pgEnum('tipo_reforma', [
  'cocina',
  'bano',
  'salon',
  'comedor',
  'integral',
  'otro',
]);

export const calidad = pgEnum('calidad', ['basica', 'media', 'premium']);

// Momento de una foto del lead: el estado antes de la reforma o el render del después.
export const fotoMomento = pgEnum('foto_momento', ['antes', 'despues']);

export const urgencia = pgEnum('urgencia', ['alta', 'media', 'baja']);

export const categoriaMaterial = pgEnum('categoria_material', [
  'suelo',
  'pared',
  'pintura',
  'mobiliario',
]);

export const unidadMedida = pgEnum('unidad_medida', ['m2', 'ml', 'ud']);

export const userRole = pgEnum('user_role', ['reformista', 'admin']);
export const userStatus = pgEnum('user_status', ['activo', 'deshabilitado']);
export const subscriptionStatus = pgEnum('subscription_status', [
  'trial',
  'activo',
  'cancelado',
  'vencido',
]);

// Cómo entrega el reformista el presupuesto al cliente final.
// 'automatico' = el funnel lo envía solo; 'revision' = se para para que el reformista lo revise/edite antes de enviar.
export const envioPresupuestoMode = pgEnum('envio_presupuesto_mode', ['automatico', 'revision']);

// Estado de moderación de un testimonio. El reformista aprueba antes de publicar.
// 'pendiente' = recién enviado por el cliente; 'publicado' = visible en la landing; 'oculto' = retirado.
export const testimonioEstado = pgEnum('testimonio_estado', ['pendiente', 'publicado', 'oculto']);

// === Estructura del flujo WhatsApp/llamada + workers (esquema "reformix-full" del equipo).
// ADITIVO: enums/tablas/columnas nuevas que usará el bot (Luisa) y los workers en la DB única.
// NO modifica los enums ni columnas existentes de la app (lead_estado, pipeline_stage, etc.).
export const estadoWa = pgEnum('estado_wa', ['sin_enviar', 'enviado', 'entregado', 'leido', 'fallido']);
export const canalContacto = pgEnum('canal_contacto', ['formulario', 'whatsapp', 'llamada']);
export const canalOrigen = pgEnum('canal_origen', [
  'formulario_web',
  'whatsapp',
  'llamada',
  'referido',
  'anuncio',
]);
export const resultadoContacto = pgEnum('resultado_contacto', [
  'exitoso',
  'no_contesta',
  'ocupado',
  'rechaza',
  'error_tecnico',
]);
export const rolMensaje = pgEnum('rol_mensaje', ['user', 'assistant', 'system']);
export const jobTipo = pgEnum('job_tipo', ['analisis_fotos', 'render', 'presupuesto_ia']);
export const jobEstado = pgEnum('job_estado', ['pendiente', 'procesando', 'completado', 'error']);
export const nivelCalificacion = pgEnum('nivel_calificacion', ['A', 'B', 'C', 'D']);
export const visitaEstado = pgEnum('visita_estado', [
  'propuesta',
  'confirmada',
  'realizada',
  'cancelada',
  'reprogramada',
]);

// Reformista (cliente del SaaS). MVP = "Reformas Ejemplo" hardcoded.
// Multi-tenant real es F1.5; la tabla ya queda lista para ello.
export const tenants = pgTable('tenants', {
  id: uuid('id').primaryKey().defaultRandom(),
  slug: text('slug').notNull().unique(),
  nombreEmpresa: text('nombre_empresa').notNull(),
  logoUrl: text('logo_url'), // data URI base64 del logo (no hay storage externo aún)
  provincia: text('provincia'),
  whatsappBusiness: text('whatsapp_business'),
  // SEO personalizable de la landing del reformista (RF-A / funnel público).
  seoTitle: text('seo_title'),
  seoDescription: text('seo_description'),
  // Bloque "Quiénes somos" opcional en el funnel del reformista.
  aboutEnabled: boolean('about_enabled').notNull().default(false),
  aboutFotoUrl: text('about_foto_url'), // data URI base64 de la foto del reformista
  aboutTexto: text('about_texto'),
  aniosExperiencia: integer('anios_experiencia'),
  // Tema visual de la landing del reformista (personalización del funnel público).
  // themePreset = id de THEME_PRESETS; themeColor = override hex opcional del color primario.
  themePreset: text('theme_preset').notNull().default('pizarra'),
  themeColor: text('theme_color'),
  // Datos de empresa para la cabecera del presupuesto (RF-D-07).
  cif: text('cif'),
  direccion: text('direccion'),
  telefono: text('telefono'),
  email: text('email'),
  web: text('web'),
  planId: uuid('plan_id').references((): AnyPgColumn => plans.id),
  subscriptionStatus: subscriptionStatus('subscription_status').notNull().default('trial'),
  envioPresupuesto: envioPresupuestoMode('envio_presupuesto').notNull().default('automatico'),
  trialEndsAt: timestamp('trial_ends_at', { withTimezone: true }),
  stripeCustomerId: text('stripe_customer_id'),
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});

export const plans = pgTable('plans', {
  id: uuid('id').primaryKey().defaultRandom(),
  slug: text('slug').notNull().unique(),
  nombre: text('nombre').notNull(),
  precioMensual: integer('precio_mensual').notNull(), // céntimos
  leadsIncluidos: integer('leads_incluidos').notNull(),
  features: jsonb('features').$type<string[]>().notNull().default([]),
  activo: boolean('activo').notNull().default(true),
});

export const users = pgTable(
  'users',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    email: text('email').notNull().unique(),
    passwordHash: text('password_hash').notNull(),
    nombre: text('nombre'),
    role: userRole('role').notNull().default('reformista'),
    tenantId: uuid('tenant_id').references(() => tenants.id, { onDelete: 'cascade' }),
    status: userStatus('status').notNull().default('activo'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [index('users_tenant_idx').on(table.tenantId)]
);

export const sessions = pgTable(
  'sessions',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    userId: uuid('user_id')
      .notNull()
      .references(() => users.id, { onDelete: 'cascade' }),
    tokenHash: text('token_hash').notNull().unique(),
    expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [index('sessions_user_idx').on(table.userId)]
);

export const leads = pgTable(
  'leads',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    tenantId: uuid('tenant_id')
      .notNull()
      .references(() => tenants.id, { onDelete: 'cascade' }),

    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),

    // Datos del cliente final (paso 2 del funnel)
    nombre: text('nombre').notNull(),
    telefono: text('telefono').notNull(),
    email: text('email').notNull(),
    provincia: text('provincia'),
    tipoReforma: tipoReforma('tipo_reforma'),

    // Consentimientos LSSI-CE + RGPD (RF-LEG-01)
    consentPrivacidad: boolean('consent_privacidad').notNull().default(false),
    consentContratacion: boolean('consent_contratacion').notNull().default(false),

    // Posición en el funnel y estado comercial
    pipelineStage: pipelineStage('pipeline_stage').notNull().default('form_completado'),
    estado: leadEstado('estado').notNull().default('nuevo'),

    // Presupuesto orientativo en céntimos de euro (evita floats)
    presupuestoEstimado: integer('presupuesto_estimado'),

    // Artefactos generados por el pipeline (RF-D-02)
    transcripcion: text('transcripcion'),
    entidades: jsonb('entidades'),
    renderUrl: text('render_url'),
    pdfUrl: text('pdf_url'),
    audioUrl: text('audio_url'),

    notas: text('notas'),

    // Cuándo el reformista pidió la opinión al cliente (RF: recogida de testimonios).
    testimonioSolicitadoAt: timestamp('testimonio_solicitado_at', { withTimezone: true }),

    // Inputs del motor de presupuesto (capturados de menos a más en el funnel)
    m2Suelo: doublePrecision('m2_suelo'),
    alturaTecho: doublePrecision('altura_techo'),
    calidadGlobal: calidad('calidad_global'),
    estructural: boolean('estructural').notNull().default(false),
    // Inputs de los extras fijos del presupuesto (no escalan con m²).
    anteriorA2000: boolean('anterior_a_2000').notNull().default(false),
    cambioDistribucion: boolean('cambio_distribucion').notNull().default(false),
    materialSelections: jsonb('material_selections')
      .$type<Record<string, string>>()
      .notNull()
      .default({}),
    desgloseSnapshot: jsonb('desglose_snapshot'),

    // Preferencias del cliente capturadas en la llamada (agente de voz)
    urgencia: urgencia('urgencia'),
    presupuestoTarget: integer('presupuesto_target'), // céntimos
    tasteText: text('taste_text'),
    preferencesSnapshot: jsonb('preferences_snapshot'),

    // --- Flujo WhatsApp/llamada (esquema reformix-full; aditivos, los rellena el bot/Luisa).
    // estadoWa nullable: null = aún sin enviar (el "nuevo" del diagrama).
    estadoWa: estadoWa('estado_wa'),
    // Paso actual de la conversación del bot (Luisa). TEXT (no enum) para que el bot evolucione
    // su vocabulario sin migración. Valores sugeridos: apertura · espacio · tamano · estilo ·
    // urgencia · presupuesto · pide_fotos · fotos_recibidas · completado · no_viable · abandonado.
    botStep: text('bot_step'),
    canalOrigen: canalOrigen('canal_origen'),
    espacio: text('espacio'), // extracción en crudo de Luisa (se normaliza a tipoReforma)
    rangoM2: text('rango_m2'), // crudo (se normaliza a m2Suelo)
    estilo: text('estilo'),
    presupuestoDeclarado: text('presupuesto_declarado'), // crudo (se normaliza a presupuestoTarget)
    viable: boolean('viable'),
    fotosSolicitadasAt: timestamp('fotos_solicitadas_at', { withTimezone: true }),
  },
  (table) => [
    index('leads_tenant_created_idx').on(table.tenantId, table.createdAt),
    index('leads_estado_idx').on(table.estado),
  ]
);

// Fotos del lead, etiquetadas por zona y momento. Las "antes" las sube el cliente (funnel o EP);
// las "despues" (renders) las devuelve el flujo de generación externo por el mismo EP de ingesta.
// zona es nullable por compatibilidad con filas antiguas (fallback al tipoReforma del lead).
export const leadFotos = pgTable('lead_fotos', {
  id: uuid('id').primaryKey().defaultRandom(),
  leadId: uuid('lead_id')
    .notNull()
    .references(() => leads.id, { onDelete: 'cascade' }),
  url: text('url').notNull(),
  momento: fotoMomento('momento').notNull().default('antes'),
  zona: tipoReforma('zona'),
  orden: integer('orden').notNull().default(0),
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});

// Datos de texto que enriquecen el perfil del lead por zona (ej. "Baño: suelo premium").
// Append-only: cada llamada al EP de ingesta puede añadir notas que el agente externo homologará.
export const leadNotas = pgTable('lead_notas', {
  id: uuid('id').primaryKey().defaultRandom(),
  leadId: uuid('lead_id')
    .notNull()
    .references(() => leads.id, { onDelete: 'cascade' }),
  zona: tipoReforma('zona'),
  texto: text('texto').notNull(),
  origen: text('origen').notNull().default('ep'), // ep | funnel | panel
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});

// Opiniones del cliente final, recogidas en el funnel de review (/opinion/[id]).
// El reformista las solicita desde el panel y aprueba antes de que salgan en su landing.
export const testimonios = pgTable(
  'testimonios',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    tenantId: uuid('tenant_id')
      .notNull()
      .references(() => tenants.id, { onDelete: 'cascade' }),
    leadId: uuid('lead_id').references(() => leads.id, { onDelete: 'set null' }),
    nombre: text('nombre').notNull(),
    contexto: text('contexto'), // p.ej. "Reforma de cocina · Madrid"
    rating: integer('rating').notNull(), // 1-5 estrellas
    texto: text('texto').notNull(),
    estado: testimonioEstado('estado').notNull().default('pendiente'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    index('testimonios_tenant_estado_idx').on(table.tenantId, table.estado),
    index('testimonios_lead_idx').on(table.leadId),
  ]
);

// Fotos adjuntas a un testimonio (el cliente sube fotos del resultado).
export const testimonioFotos = pgTable('testimonio_fotos', {
  id: uuid('id').primaryKey().defaultRandom(),
  testimonioId: uuid('testimonio_id')
    .notNull()
    .references(() => testimonios.id, { onDelete: 'cascade' }),
  url: text('url').notNull(),
  orden: integer('orden').notNull().default(0),
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});

// Galería de trabajos del reformista (fotos de reformas hechas), visible en su landing.
export const galeriaFotos = pgTable(
  'galeria_fotos',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    tenantId: uuid('tenant_id')
      .notNull()
      .references(() => tenants.id, { onDelete: 'cascade' }),
    url: text('url').notNull(), // data URI base64 (no hay storage externo aún)
    titulo: text('titulo'),
    orden: integer('orden').notNull().default(0),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [index('galeria_tenant_idx').on(table.tenantId)]
);

// Histórico de cambios de estado comercial (RF-D-03: persistir y reflejar)
export const leadEstadoHistory = pgTable('lead_estado_history', {
  id: uuid('id').primaryKey().defaultRandom(),
  leadId: uuid('lead_id')
    .notNull()
    .references(() => leads.id, { onDelete: 'cascade' }),
  estado: leadEstado('estado').notNull(),
  changedAt: timestamp('changed_at', { withTimezone: true }).notNull().defaultNow(),
  changedBy: text('changed_by'),
});

// Timeline del funnel: una fila por cada paso alcanzado.
// Permite ver dónde está el lead y cuál es el siguiente paso.
export const leadPipelineEventos = pgTable('lead_pipeline_eventos', {
  id: uuid('id').primaryKey().defaultRandom(),
  leadId: uuid('lead_id')
    .notNull()
    .references(() => leads.id, { onDelete: 'cascade' }),
  stage: pipelineStage('stage').notNull(),
  occurredAt: timestamp('occurred_at', { withTimezone: true }).notNull().defaultNow(),
  metadata: jsonb('metadata'),
});

// Bucle de precisión (RF-D-04): precio final firmado vs estimado.
export const precisionHistory = pgTable('precision_history', {
  id: uuid('id').primaryKey().defaultRandom(),
  leadId: uuid('lead_id')
    .notNull()
    .references(() => leads.id, { onDelete: 'cascade' }),
  estimated: integer('estimated').notNull(), // céntimos
  final: integer('final').notNull(), // céntimos
  deltaPct: numeric('delta_pct', { precision: 6, scale: 2 }).notNull(),
  createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
});

// Configuración de precios del reformista (1 fila por tenant). RF-D-07.
export const pricingConfig = pgTable('pricing_config', {
  id: uuid('id').primaryKey().defaultRandom(),
  tenantId: uuid('tenant_id')
    .notNull()
    .references(() => tenants.id, { onDelete: 'cascade' })
    .unique(),
  alturaTechoDefault: doublePrecision('altura_techo_default').notNull().default(2.5),
  factorZona: jsonb('factor_zona').$type<Record<string, number>>().notNull().default({}),
  manoObra: jsonb('mano_obra').$type<Record<string, number>>().notNull().default({}),
  // Extras fijos en céntimos: { tuberias, boletin, distribucion }.
  extras: jsonb('extras')
    .$type<{ tuberias: number; boletin: number; distribucion: number }>()
    .notNull()
    .default({ tuberias: 0, boletin: 0, distribucion: 0 }),
  updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
});

// Catálogo de materiales del reformista. Importable por CSV.
export const catalogItems = pgTable(
  'catalog_items',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    tenantId: uuid('tenant_id')
      .notNull()
      .references(() => tenants.id, { onDelete: 'cascade' }),
    categoria: categoriaMaterial('categoria').notNull(),
    nombre: text('nombre').notNull(),
    calidad: calidad('calidad').notNull(),
    precioUnit: integer('precio_unit').notNull(), // céntimos por unidad
    unidad: unidadMedida('unidad').notNull(),
    descriptorRender: text('descriptor_render').notNull().default(''),
    esDefault: boolean('es_default').notNull().default(false),
    sku: text('sku').notNull(),
  },
  (table) => [
    index('catalog_tenant_idx').on(table.tenantId),
    uniqueIndex('catalog_tenant_sku_idx').on(table.tenantId, table.sku),
  ]
);

// === Tablas del flujo WhatsApp/llamada + workers (esquema reformix-full; aditivas).
// Las escribe el bot (Luisa) y los workers; referencian nuestros leads/users/tenants en la DB única.

// Historial de la conversación de WhatsApp del bot con el lead.
export const conversacionWhatsapp = pgTable(
  'conversacion_whatsapp',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    leadId: uuid('lead_id')
      .notNull()
      .references(() => leads.id, { onDelete: 'cascade' }),
    rol: rolMensaje('rol').notNull(),
    mensaje: text('mensaje').notNull(),
    mediaType: text('media_type'),
    mediaUrl: text('media_url'),
    transcripcionAudio: text('transcripcion_audio'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    index('idx_conversacion_whatsapp_lead_id').on(table.leadId),
    index('idx_conversacion_whatsapp_created_at').on(table.createdAt),
  ]
);

// Intentos de contacto multicanal (formulario/whatsapp/llamada).
export const intentosContacto = pgTable(
  'intentos_contacto',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    leadId: uuid('lead_id')
      .notNull()
      .references(() => leads.id, { onDelete: 'cascade' }),
    canal: canalContacto('canal').notNull(),
    resultado: resultadoContacto('resultado'),
    completado: boolean('completado').notNull().default(false),
    numeroIntento: integer('numero_intento').notNull(),
    duracionSeg: integer('duracion_seg'),
    intentadoAt: timestamp('intentado_at', { withTimezone: true }).notNull().defaultNow(),
    notas: text('notas'),
    metadata: jsonb('metadata'),
  },
  (table) => [index('idx_intentos_contacto_lead_id').on(table.leadId)]
);

// Calificación del lead (score 0-100 + nivel A/B/C/D). Una por lead.
export const leadCalificacion = pgTable(
  'lead_calificacion',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    leadId: uuid('lead_id')
      .notNull()
      .unique()
      .references(() => leads.id, { onDelete: 'cascade' }),
    score: integer('score'),
    nivel: nivelCalificacion('nivel'),
    criterios: jsonb('criterios'),
    notasAgente: text('notas_agente'),
    calificadoPor: uuid('calificado_por').references(() => users.id, { onDelete: 'set null' }),
    calificadoAt: timestamp('calificado_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    index('idx_lead_calificacion_lead_id').on(table.leadId),
    check('lead_calificacion_score_check', sql`${table.score} >= 0 AND ${table.score} <= 100`),
  ]
);

// Visitas agendadas por el reformista.
export const visitas = pgTable(
  'visitas',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    leadId: uuid('lead_id')
      .notNull()
      .references(() => leads.id, { onDelete: 'cascade' }),
    tenantId: uuid('tenant_id')
      .notNull()
      .references(() => tenants.id, { onDelete: 'cascade' }),
    fechaPropuesta: timestamp('fecha_propuesta', { withTimezone: true }),
    fechaConfirmada: timestamp('fecha_confirmada', { withTimezone: true }),
    estado: visitaEstado('estado').notNull().default('propuesta'),
    direccion: text('direccion'),
    notas: text('notas'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    index('idx_visitas_lead_id').on(table.leadId),
    index('idx_visitas_tenant_id').on(table.tenantId),
  ]
);

// Cola de trabajos async de los workers (análisis de fotos, render, presupuesto IA).
export const workerJobs = pgTable(
  'worker_jobs',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    leadId: uuid('lead_id')
      .notNull()
      .references(() => leads.id, { onDelete: 'cascade' }),
    tipo: jobTipo('tipo').notNull(),
    estadoJob: jobEstado('estado_job').notNull().default('pendiente'),
    payload: jsonb('payload').notNull(),
    webhookUrl: text('webhook_url'),
    resultadoUrl: text('resultado_url'),
    intentos: integer('intentos').notNull().default(0),
    errorMsg: text('error_msg'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    completedAt: timestamp('completed_at', { withTimezone: true }),
  },
  (table) => [
    index('idx_worker_jobs_lead_id').on(table.leadId),
    index('idx_worker_jobs_estado').on(table.estadoJob),
    index('idx_worker_jobs_tipo').on(table.tipo),
  ]
);

export type Tenant = typeof tenants.$inferSelect;
export type Lead = typeof leads.$inferSelect;
export type NewLead = typeof leads.$inferInsert;
export type LeadFoto = typeof leadFotos.$inferSelect;
export type NewLeadFoto = typeof leadFotos.$inferInsert;
export type LeadNota = typeof leadNotas.$inferSelect;
export type NewLeadNota = typeof leadNotas.$inferInsert;
export type ConversacionWhatsapp = typeof conversacionWhatsapp.$inferSelect;
export type IntentoContacto = typeof intentosContacto.$inferSelect;
export type LeadCalificacion = typeof leadCalificacion.$inferSelect;
export type Visita = typeof visitas.$inferSelect;
export type WorkerJob = typeof workerJobs.$inferSelect;
export type Testimonio = typeof testimonios.$inferSelect;
export type NewTestimonio = typeof testimonios.$inferInsert;
export type TestimonioFoto = typeof testimonioFotos.$inferSelect;
export type GaleriaFoto = typeof galeriaFotos.$inferSelect;
export type LeadEstadoHistory = typeof leadEstadoHistory.$inferSelect;
export type LeadPipelineEvento = typeof leadPipelineEventos.$inferSelect;
export type PrecisionHistory = typeof precisionHistory.$inferSelect;
export type PricingConfigRow = typeof pricingConfig.$inferSelect;
export type CatalogItemRow = typeof catalogItems.$inferSelect;
export type NewCatalogItem = typeof catalogItems.$inferInsert;
export type Plan = typeof plans.$inferSelect;
export type User = typeof users.$inferSelect;
export type NewUser = typeof users.$inferInsert;
export type Session = typeof sessions.$inferSelect;
