import {
  pgTable,
  text,
  integer,
  numeric,
  timestamp,
  boolean,
  jsonb,
  primaryKey,
  uniqueIndex,
  index,
} from "drizzle-orm/pg-core";
import { relations } from "drizzle-orm";
import { nanoid } from "nanoid";

// ============ CLIENTS ============
export const clients = pgTable("clients", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  name: text("name").notNull(),
  brand_name: text("brand_name").notNull(),
  brief: text("brief").notNull(),
  // Contact fields (Phase v2.3) — carried over from a converted lead and used
  // by the Email & Accesso (OTP) milestone. Admin-only, never exposed publicly.
  email: text("email"),
  phone: text("phone"),
  // token is SEPARATE from id — rotatable secret for client link access
  token: text("token")
    .notNull()
    .unique()
    .$defaultFn(() => nanoid()),
  // slug è opzionale, univoco, URL-safe (es. mario-rossi) — se assente, il link usa il token
  slug: text("slug").unique(),
  // accepted_total rimane per compatibilità — il valore authoritative si sposta su projects
  accepted_total: numeric("accepted_total", { precision: 10, scale: 2 }).default(
    "0"
  ),
  archived: boolean("archived").notNull().default(false),
  // Conversazioni inbox: timestamp of the admin's last read of this client's
  // conversation. NULL = never read (treated as unread). Set via markConversationRead.
  admin_last_read_at: timestamp("admin_last_read_at", { withTimezone: true }),
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ PROJECTS ============
export const projects = pgTable("projects", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  client_id: text("client_id")
    .notNull()
    .references(() => clients.id, { onDelete: "cascade" }),
  name: text("name").notNull(), // brand/project name
  accepted_total: numeric("accepted_total", { precision: 10, scale: 2 }).default("0"),
  archived: boolean("archived").notNull().default(false),
  offer_id: text("offer_id")
    .references(() => offer_micros.id, { onDelete: "set null" }),
  created_from_lead_id: text("created_from_lead_id"),
  created_at: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
});

// ============ PHASES ============
export const phases = pgTable("phases", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  project_id: text("project_id")
    .notNull()
    .references(() => projects.id, { onDelete: "cascade" }),
  title: text("title").notNull(),
  sort_order: integer("sort_order").notNull().default(0),
  status: text("status").notNull().default("upcoming"), // upcoming | active | done
  offer_phase_id: text("offer_phase_id")
    .references(() => offer_phases.id, { onDelete: "set null" }),
});

// ============ TASKS ============
export const tasks = pgTable("tasks", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  phase_id: text("phase_id")
    .notNull()
    .references(() => phases.id, { onDelete: "cascade" }),
  title: text("title").notNull(),
  description: text("description"),
  status: text("status").notNull().default("todo"), // todo | in_progress | done
  sort_order: integer("sort_order").notNull().default(0),
});

// ============ DELIVERABLES ============
export const deliverables = pgTable("deliverables", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  task_id: text("task_id")
    .notNull()
    .references(() => tasks.id, { onDelete: "cascade" }),
  title: text("title").notNull(),
  url: text("url"), // external link only — no file hosting in v1
  status: text("status").notNull().default("pending"), // pending | submitted | approved
  // approved_at is IMMUTABLE once set — audit trail, cannot be unset by client
  approved_at: timestamp("approved_at", { withTimezone: true }),
});

// ============ COMMENTS ============
export const comments = pgTable("comments", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  entity_type: text("entity_type").notNull(), // task | deliverable
  entity_id: text("entity_id").notNull(),
  author: text("author").notNull(), // client | admin
  body: text("body").notNull(),
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ TAGS (polymorphic — services now, leads in Phase 14) ============
// entity_type scopes the tag pool (D-06): "services" tags and "leads" tags are
// separate pools even though they share this table. No `color` column — badge
// color is derived deterministically from `name` via hash (D-07).
export const tags = pgTable(
  "tags",
  {
    id: text("id")
      .primaryKey()
      .$defaultFn(() => nanoid()),
    entity_type: text("entity_type").notNull(), // "services" | "leads" (Phase 14)
    entity_id: text("entity_id").notNull(),
    name: text("name").notNull(),
    created_at: timestamp("created_at", { withTimezone: true })
      .notNull()
      .defaultNow(),
  },
  (t) => ({
    entityTagUnique: uniqueIndex("tags_entity_name_unique").on(
      t.entity_type,
      t.entity_id,
      t.name
    ),
    entityIdx: index("tags_entity_idx").on(t.entity_type, t.entity_id),
  })
);

// ============ PAYMENTS ============
export const payments = pgTable("payments", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  project_id: text("project_id")
    .notNull()
    .references(() => projects.id, { onDelete: "cascade" }),
  label: text("label").notNull(), // "Acconto 50%" | "Saldo 50%"
  amount: numeric("amount", { precision: 10, scale: 2 }).notNull(),
  percent: numeric("percent", { precision: 5, scale: 2 }), // nullable — % of total (for rescaling); null = legacy row
  status: text("status").notNull().default("da_saldare"), // da_saldare | inviata | saldato
  paid_at: timestamp("paid_at", { withTimezone: true }),
});

// ============ DOCUMENTS ============
export const documents = pgTable("documents", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  project_id: text("project_id")
    .notNull()
    .references(() => projects.id, { onDelete: "cascade" }),
  label: text("label").notNull(),
  url: text("url").notNull(), // external URL only — no file hosting in v1
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ NOTES (Decision Log — admin writes, client reads) ============
export const notes = pgTable("notes", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  project_id: text("project_id")
    .notNull()
    .references(() => projects.id, { onDelete: "cascade" }),
  body: text("body").notNull(),
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ TIME ENTRIES (admin time tracking per project) ============
export const time_entries = pgTable("time_entries", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  project_id: text("project_id")
    .notNull()
    .references(() => projects.id, { onDelete: "cascade" }),
  started_at: timestamp("started_at", { withTimezone: true }).notNull().defaultNow(),
  ended_at: timestamp("ended_at", { withTimezone: true }),
  duration_seconds: integer("duration_seconds"), // set on stop
});

// ============ SERVICE CATALOG (admin-only, used for quote generation) ============
export const service_catalog = pgTable("service_catalog", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  name: text("name").notNull(),
  description: text("description"),
  unit_price: numeric("unit_price", { precision: 10, scale: 2 }).notNull(),
  active: boolean("active").notNull().default(true),
});

// ============ SERVICES (UNIFIED CATALOG — replaces service_catalog + offer_services) ============
// migrated_from/migrated_id provide audit trail for safe rollback during the
// expand-contract migration (Phase 7 expand; Phase 8 begins contract on offer side).
export const services = pgTable("services", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  name: text("name").notNull(),
  description: text("description"),
  unit_price: numeric("unit_price", { precision: 10, scale: 2 }).notNull(),
  category: text("category"),             // single-select option (shared pool derived from distinct values)
  fase: text("fase"),                     // single-select option — offer lifecycle phase (Notion-style)
  active: boolean("active").notNull().default(true),
  migrated_from: text("migrated_from"),   // "service_catalog" | "offer_services" | null (new rows after Phase 7)
  migrated_id: text("migrated_id"),       // original id from source table, null for new rows
  created_at: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
});

export const servicesRelations = relations(services, (_) => ({
  // No FK relations yet in Phase 7 — quote_items and offer_micro_services
  // continue to reference service_catalog/offer_services until Phase 8.
}));

// ============ QUOTE ITEMS (admin-only — NEVER exposed via client API) ============
export const quote_items = pgTable("quote_items", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  project_id: text("project_id")
    .references(() => projects.id, { onDelete: "cascade" }), // legacy: for old quote_items tied to projects (Phase 1-8)
  quote_id: text("quote_id")
    .references(() => quotes.id, { onDelete: "cascade" }), // which quote owns this item (nullable for legacy)
  offer_phase_id: text("offer_phase_id")
    .references(() => offer_phases.id, { onDelete: "restrict" }), // which phase this service is in (nullable for legacy)
  service_id: text("service_id")
    .references(() => services.id, { onDelete: "restrict" }), // nullable for custom items
  quantity: numeric("quantity", { precision: 10, scale: 2 }).notNull(),
  unit_price: numeric("unit_price", { precision: 10, scale: 2 }).notNull(), // snapshot at time of quote
  subtotal: numeric("subtotal", { precision: 10, scale: 2 }).notNull(),
  custom_label: text("custom_label"), // for custom items without catalog entry
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ SETTINGS (global admin settings — key-value store) ============
export const settings = pgTable("settings", {
  key: text("key").primaryKey(),
  value: text("value").notNull(),
  updated_at: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
});

// ============ OFFER MACROS ============
// Phase 12 additive columns (Offer Editor — Tier A/B/C, Tag & Prezzo Pubblico):
// description, category, ticket, is_archived, and the 5 structured
// transformation-promise fields (cliente_ideale/risultato/tempo/pain/metodo).
// transformation_promise (legacy, free-text) stays untouched.
export const offer_macros = pgTable("offer_macros", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  internal_name: text("internal_name").notNull(),
  public_name: text("public_name").notNull(),
  transformation_promise: text("transformation_promise"),
  // Phase 12 additive fields below
  description: text("description"), // short description shown on offer cards
  category: text("category"), // single-select "Categoria" (Entry/Signature/Retainer Offer) — OFFER-15/18
  ticket: text("ticket"), // single-select "Ticket" (Low/Mid/High Ticket) — OFFER-15
  offer_type: text("offer_type").notNull().default("una_tantum"), // una_tantum | retainer (v2.3)
  is_archived: boolean("is_archived").notNull().default(false), // OFFER-18 archive flag
  cliente_ideale: text("cliente_ideale"), // "Aiuto: [Cliente Ideale]"
  risultato: text("risultato"), // "A ottenere: [Risultato]"
  tempo: text("tempo"), // "In: [tempo]"
  pain: text("pain"), // "Senza: [Pain]"
  metodo: text("metodo"), // "Grazie a: [Metodo]"
  sort_order: integer("sort_order").notNull().default(0),
  created_at: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
});

// ============ OFFER MICROS ============
export const offer_micros = pgTable("offer_micros", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  macro_id: text("macro_id")
    .notNull()
    .references(() => offer_macros.id, { onDelete: "cascade" }),
  internal_name: text("internal_name").notNull(),
  public_name: text("public_name").notNull(),
  transformation_promise: text("transformation_promise"),
  duration_months: integer("duration_months").notNull().default(1),
  sort_order: integer("sort_order").notNull().default(0),
  // Phase 12 additive fields below.
  // tier_letter: nullable, values constrained to 'A'|'B'|'C' via a CHECK
  // constraint at the SQL level (migration 0008) — not enforced in Drizzle
  // (no native CHECK helper in this project's pg-core version); validated in
  // Zod at the server-action layer (Plan 03).
  tier_letter: text("tier_letter"),
  // public_price: manual public price per tier (D-5/OFFER-16), independent of
  // the computed services total (computed at query time, never stored).
  public_price: numeric("public_price", { precision: 10, scale: 2 }),
});

// ============ OFFER SERVICES (distinct from service_catalog — marketing/transformation semantics) ============
export const offer_services = pgTable("offer_services", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  name: text("name").notNull(),
  price: numeric("price", { precision: 10, scale: 2 }).notNull(),
  transformation_description: text("transformation_description"),
  active: boolean("active").notNull().default(true),
});

// ============ OFFER MICRO SERVICES (junction: offer_micros <-> offer_services) ============
export const offer_micro_services = pgTable(
  "offer_micro_services",
  {
    micro_id: text("micro_id")
      .notNull()
      .references(() => offer_micros.id, { onDelete: "cascade" }),
    service_id: text("service_id")
      .notNull()
      .references(() => offer_services.id, { onDelete: "cascade" }),
  },
  (t) => ({
    pk: primaryKey({ columns: [t.micro_id, t.service_id] }),
  })
);

// ============ OFFER TIER SERVICES (Phase 12 — junction: offer_micros <-> services) ============
// Additive replacement for the legacy offer_micro_services (which points to the
// deprecated offer_services table). This junction connects a tier (offer_micros row
// with tier_letter set) to the unified services catalog (Phase 11). Do NOT modify
// offer_micro_services — it remains untouched for legacy data.
export const offer_tier_services = pgTable(
  "offer_tier_services",
  {
    tier_id: text("tier_id")
      .notNull()
      .references(() => offer_micros.id, { onDelete: "cascade" }),
    service_id: text("service_id")
      .notNull()
      .references(() => services.id, { onDelete: "cascade" }),
    created_at: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
  },
  (t) => ({
    pk: primaryKey({ columns: [t.tier_id, t.service_id] }),
    tierIdx: index("offer_tier_services_tier_idx").on(t.tier_id),
  })
);

// ============ PROJECT OFFERS (assignment of micro-offer to project) ============
export const project_offers = pgTable("project_offers", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  project_id: text("project_id")
    .notNull()
    .references(() => projects.id, { onDelete: "cascade" }),
  micro_id: text("micro_id")
    .notNull()
    .references(() => offer_micros.id, { onDelete: "restrict" }),
  // NOT NULL with defaultNow — required for forecast computation (null start_date breaks forecast)
  start_date: timestamp("start_date", { withTimezone: true }).notNull().defaultNow(),
  // Offer-level accepted total — separate from projects.accepted_total (quote builder total)
  accepted_total: numeric("accepted_total", { precision: 10, scale: 2 }),
  created_at: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
});

// ============ OFFER PHASES (hierarchical breakdown of offer micros) ============
export const offer_phases = pgTable("offer_phases", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  micro_id: text("micro_id")
    .notNull()
    .references(() => offer_micros.id, { onDelete: "cascade" }),
  title: text("title").notNull(),
  description: text("description"),
  sort_order: integer("sort_order").notNull().default(0),
  duration_weeks: integer("duration_weeks"),
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ OFFER PHASE SERVICES (junction: offer_phases <-> services) ============
export const offer_phase_services = pgTable(
  "offer_phase_services",
  {
    phase_id: text("phase_id")
      .notNull()
      .references(() => offer_phases.id, { onDelete: "cascade" }),
    service_id: text("service_id")
      .notNull()
      .references(() => services.id, { onDelete: "cascade" }),
  },
  (t) => ({
    pk: primaryKey({ columns: [t.phase_id, t.service_id] }),
  })
);

// ============ QUOTES (separate header from line items) ============
export const quotes = pgTable("quotes", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  lead_id: text("lead_id")
    .references(() => leads.id, { onDelete: "cascade" }),
  client_id: text("client_id")
    .references(() => clients.id, { onDelete: "cascade" }),
  token: text("token")
    .notNull()
    .unique()
    .$defaultFn(() => nanoid()),
  offer_micro_id: text("offer_micro_id")
    .notNull()
    .references(() => offer_micros.id, { onDelete: "restrict" }),
  state: text("state").notNull().default("draft"), // draft | sent | viewed | accepted | rejected
  accepted_total: numeric("accepted_total", { precision: 10, scale: 2 }).notNull(),
  accepted_at: timestamp("accepted_at", { withTimezone: true }), // immutable once set; NULL means not yet accepted
  client_email: text("client_email"), // captured on accept
  client_notes: text("client_notes"), // captured on accept
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
  updated_at: timestamp("updated_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ LEADS TABLE (CRM — Phase 10) ============
export const leads = pgTable("leads", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  name: text("name").notNull(),
  email: text("email"),
  phone: text("phone"),
  company: text("company"),
  status: text("status")
    .notNull()
    .default("contacted"), // contacted | qualified | proposal_sent | negotiating | won | lost
  last_contact_date: timestamp("last_contact_date", { withTimezone: true }),
  next_action: text("next_action"),
  next_action_date: timestamp("next_action_date", { withTimezone: true }),
  notes: text("notes"),
  // Archive flag (v2.3) — a converted lead is hidden from the pipeline while
  // keeping its "won" status, so the board doesn't fill up over time.
  archived: boolean("archived").notNull().default(false),
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
  updated_at: timestamp("updated_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ ACTIVITIES TABLE (CRM interaction history) ============
export const activities = pgTable("activities", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  lead_id: text("lead_id")
    .notNull()
    .references(() => leads.id, { onDelete: "cascade" }),
  type: text("type")
    .notNull(), // call | email | meeting | note
  duration_minutes: integer("duration_minutes"),
  notes: text("notes").notNull(),
  activity_date: timestamp("activity_date", { withTimezone: true })
    .notNull(),
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ REMINDERS TABLE (CRM follow-up reminders) ============
export const reminders = pgTable("reminders", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  lead_id: text("lead_id")
    .notNull()
    .references(() => leads.id, { onDelete: "cascade" }),
  title: text("title").notNull(),
  description: text("description"),
  due_date: timestamp("due_date", { withTimezone: true })
    .notNull(),
  completed_at: timestamp("completed_at", { withTimezone: true }),
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ CLIENT TRANSCRIPTS TABLE (Knowledge Base — Phase 20) ============
// Transcript datati delle call, multipli per lead o cliente.
// lead_id e client_id sono entrambi nullable (D-01): un transcript può appartenere
// a un lead pre-conversione (Phase 20 UI) o a un cliente post-conversione (futuro).
export const clientTranscripts = pgTable("client_transcripts", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  lead_id: text("lead_id")
    .references(() => leads.id, { onDelete: "cascade" }),
  client_id: text("client_id")
    .references(() => clients.id, { onDelete: "cascade" }),
  title: text("title"),
  content: text("content").notNull(),
  call_date: text("call_date").notNull(), // "YYYY-MM-DD" — coerente con <input type="date">
  created_at: timestamp("created_at", { withTimezone: true })
    .notNull()
    .defaultNow(),
});

// ============ PROPOSALS TABLE (Preventivo AI — Phase 21/22) ============
// Preventivo generato dall'agente AI e pubblicato come pagina pubblica
// navigabile su /preventivo/[slug]. content (jsonb) contiene l'intero
// ProposalContent assemblato (sezioni AI + offerta + config consulente).
// lead_id/client_id nullable (ON DELETE SET NULL — non perdere la proposta se
// il lead viene rimosso). offer_macro_id RESTRICT — la proposta riferisce
// l'offerta sorgente. accepted_at IMMUTABILE una volta valorizzato.
export const proposals = pgTable("proposals", {
  id: text("id")
    .primaryKey()
    .$defaultFn(() => nanoid()),
  slug: text("slug")
    .notNull()
    .unique()
    .$defaultFn(() => nanoid()),
  lead_id: text("lead_id").references(() => leads.id, { onDelete: "set null" }),
  client_id: text("client_id").references(() => clients.id, { onDelete: "set null" }),
  offer_macro_id: text("offer_macro_id")
    .notNull()
    .references(() => offer_macros.id, { onDelete: "restrict" }),
  title: text("title"),
  // Intero ProposalContent assemblato. Validato a runtime via Zod
  // (src/lib/proposal/schema.ts); jsonb gestito da postgres-js (parse automatico).
  content: jsonb("content").notNull(),
  model: text("model"), // es. "claude-opus-4-8"
  state: text("state").notNull().default("draft"), // draft | published | accepted | rejected
  selected_tier: text("selected_tier"), // 'A' | 'B' | 'C' — CHECK a livello SQL (migration 0010)
  accepted_at: timestamp("accepted_at", { withTimezone: true }), // immutable once set
  client_email: text("client_email"),
  client_notes: text("client_notes"),
  created_at: timestamp("created_at", { withTimezone: true }).notNull().defaultNow(),
  updated_at: timestamp("updated_at", { withTimezone: true }).notNull().defaultNow(),
});

// ============ RELATIONS ============

export const clientsRelations = relations(clients, ({ many }) => ({
  projects: many(projects),
  transcripts: many(clientTranscripts),
  proposals: many(proposals),
}));

export const projectsRelations = relations(projects, ({ one, many }) => ({
  client: one(clients, { fields: [projects.client_id], references: [clients.id] }),
  offer: one(offer_micros, { fields: [projects.offer_id], references: [offer_micros.id] }),
  phases: many(phases),
  payments: many(payments),
  documents: many(documents),
  notes: many(notes),
  quote_items: many(quote_items),
  time_entries: many(time_entries),
  projectOffers: many(project_offers),
}));

export const phasesRelations = relations(phases, ({ one, many }) => ({
  project: one(projects, { fields: [phases.project_id], references: [projects.id] }),
  offerPhase: one(offer_phases, { fields: [phases.offer_phase_id], references: [offer_phases.id] }),
  tasks: many(tasks),
}));

export const tasksRelations = relations(tasks, ({ one, many }) => ({
  phase: one(phases, { fields: [tasks.phase_id], references: [phases.id] }),
  deliverables: many(deliverables),
}));

export const deliverablesRelations = relations(deliverables, ({ one }) => ({
  task: one(tasks, { fields: [deliverables.task_id], references: [tasks.id] }),
}));

export const commentsRelations = relations(comments, (_) => ({
  // Polymorphic: no direct FK relation — entity_type + entity_id used at query time
}));

export const tagsRelations = relations(tags, (_) => ({
  // Polymorphic: no direct FK relation — entity_type + entity_id used at query time
}));

export const paymentsRelations = relations(payments, ({ one }) => ({
  project: one(projects, {
    fields: [payments.project_id],
    references: [projects.id],
  }),
}));

export const documentsRelations = relations(documents, ({ one }) => ({
  project: one(projects, {
    fields: [documents.project_id],
    references: [projects.id],
  }),
}));

export const notesRelations = relations(notes, ({ one }) => ({
  project: one(projects, { fields: [notes.project_id], references: [projects.id] }),
}));

export const timeEntriesRelations = relations(time_entries, ({ one }) => ({
  project: one(projects, { fields: [time_entries.project_id], references: [projects.id] }),
}));

export const quoteItemsRelations = relations(quote_items, ({ one }) => ({
  project: one(projects, {
    fields: [quote_items.project_id],
    references: [projects.id],
  }),
  quote: one(quotes, {
    fields: [quote_items.quote_id],
    references: [quotes.id],
  }),
  service: one(services, {
    fields: [quote_items.service_id],
    references: [services.id],
  }),
  offerPhase: one(offer_phases, {
    fields: [quote_items.offer_phase_id],
    references: [offer_phases.id],
  }),
}));

export const serviceCatalogRelations = relations(
  service_catalog,
  ({ many }) => ({
    quote_items: many(quote_items),
  })
);

export const offerMacrosRelations = relations(offer_macros, ({ many }) => ({
  micros: many(offer_micros),
}));

export const offerMicrosRelations = relations(offer_micros, ({ one, many }) => ({
  macro: one(offer_macros, { fields: [offer_micros.macro_id], references: [offer_macros.id] }),
  services: many(offer_micro_services),
  tierServices: many(offer_tier_services),
  projectOffers: many(project_offers),
}));

export const offerServicesRelations = relations(offer_services, ({ many }) => ({
  microAssignments: many(offer_micro_services),
}));

export const offerMicroServicesRelations = relations(offer_micro_services, ({ one }) => ({
  micro: one(offer_micros, { fields: [offer_micro_services.micro_id], references: [offer_micros.id] }),
  service: one(offer_services, { fields: [offer_micro_services.service_id], references: [offer_services.id] }),
}));

export const offerTierServicesRelations = relations(offer_tier_services, ({ one }) => ({
  tier: one(offer_micros, { fields: [offer_tier_services.tier_id], references: [offer_micros.id] }),
  service: one(services, { fields: [offer_tier_services.service_id], references: [services.id] }),
}));

export const projectOffersRelations = relations(project_offers, ({ one }) => ({
  project: one(projects, { fields: [project_offers.project_id], references: [projects.id] }),
  micro: one(offer_micros, { fields: [project_offers.micro_id], references: [offer_micros.id] }),
}));

export const offerPhasesRelations = relations(offer_phases, ({ one, many }) => ({
  micro: one(offer_micros, { fields: [offer_phases.micro_id], references: [offer_micros.id] }),
  services: many(offer_phase_services),
  quoteItems: many(quote_items),
}));

export const offerPhaseServicesRelations = relations(offer_phase_services, ({ one }) => ({
  phase: one(offer_phases, { fields: [offer_phase_services.phase_id], references: [offer_phases.id] }),
  service: one(services, { fields: [offer_phase_services.service_id], references: [services.id] }),
}));

export const leadsRelations = relations(leads, ({ many }) => ({
  quotes: many(quotes),
  activities: many(activities),
  reminders: many(reminders),
  transcripts: many(clientTranscripts),
  proposals: many(proposals),
}));

export const activitiesRelations = relations(activities, ({ one }) => ({
  lead: one(leads, { fields: [activities.lead_id], references: [leads.id] }),
}));

export const remindersRelations = relations(reminders, ({ one }) => ({
  lead: one(leads, { fields: [reminders.lead_id], references: [leads.id] }),
}));

export const clientTranscriptsRelations = relations(clientTranscripts, ({ one }) => ({
  lead: one(leads, {
    fields: [clientTranscripts.lead_id],
    references: [leads.id],
  }),
  client: one(clients, {
    fields: [clientTranscripts.client_id],
    references: [clients.id],
  }),
}));

export const quotesRelations = relations(quotes, ({ one, many }) => ({
  lead: one(leads, { fields: [quotes.lead_id], references: [leads.id] }),
  client: one(clients, { fields: [quotes.client_id], references: [clients.id] }),
  offerMicro: one(offer_micros, { fields: [quotes.offer_micro_id], references: [offer_micros.id] }),
  quoteItems: many(quote_items),
}));

export const proposalsRelations = relations(proposals, ({ one }) => ({
  lead: one(leads, { fields: [proposals.lead_id], references: [leads.id] }),
  client: one(clients, { fields: [proposals.client_id], references: [clients.id] }),
  offerMacro: one(offer_macros, {
    fields: [proposals.offer_macro_id],
    references: [offer_macros.id],
  }),
}));

// ============ TYPESCRIPT TYPES (for use in API routes and Server Components) ============

export type Client = typeof clients.$inferSelect;
export type NewClient = typeof clients.$inferInsert;
export type Project = typeof projects.$inferSelect;
export type NewProject = typeof projects.$inferInsert;
export type Phase = typeof phases.$inferSelect;
export type NewPhase = typeof phases.$inferInsert;
export type Task = typeof tasks.$inferSelect;
export type NewTask = typeof tasks.$inferInsert;
export type Deliverable = typeof deliverables.$inferSelect;
export type NewDeliverable = typeof deliverables.$inferInsert;
export type Comment = typeof comments.$inferSelect;
export type NewComment = typeof comments.$inferInsert;
export type Tag = typeof tags.$inferSelect;
export type NewTag = typeof tags.$inferInsert;
export type Payment = typeof payments.$inferSelect;
export type NewPayment = typeof payments.$inferInsert;
export type Document = typeof documents.$inferSelect;
export type NewDocument = typeof documents.$inferInsert;
export type Note = typeof notes.$inferSelect;
export type NewNote = typeof notes.$inferInsert;
export type Service = typeof services.$inferSelect;
export type NewService = typeof services.$inferInsert;
export type ServiceCatalog = typeof service_catalog.$inferSelect;
export type NewServiceCatalog = typeof service_catalog.$inferInsert;
export type QuoteItem = typeof quote_items.$inferSelect;
export type NewQuoteItem = typeof quote_items.$inferInsert;
export type TimeEntry = typeof time_entries.$inferSelect;
export type NewTimeEntry = typeof time_entries.$inferInsert;
export type Setting = typeof settings.$inferSelect;
export type NewSetting = typeof settings.$inferInsert;
export type OfferMacro = typeof offer_macros.$inferSelect;
export type NewOfferMacro = typeof offer_macros.$inferInsert;
export type OfferMicro = typeof offer_micros.$inferSelect;
export type NewOfferMicro = typeof offer_micros.$inferInsert;
export type OfferService = typeof offer_services.$inferSelect;
export type NewOfferService = typeof offer_services.$inferInsert;
export type OfferMicroService = typeof offer_micro_services.$inferSelect;
export type NewOfferMicroService = typeof offer_micro_services.$inferInsert;
export type OfferTierService = typeof offer_tier_services.$inferSelect;
export type NewOfferTierService = typeof offer_tier_services.$inferInsert;
export type ProjectOffer = typeof project_offers.$inferSelect;
export type NewProjectOffer = typeof project_offers.$inferInsert;
export type OfferPhase = typeof offer_phases.$inferSelect;
export type NewOfferPhase = typeof offer_phases.$inferInsert;
export type OfferPhaseService = typeof offer_phase_services.$inferSelect;
export type NewOfferPhaseService = typeof offer_phase_services.$inferInsert;
export type Quote = typeof quotes.$inferSelect;
export type NewQuote = typeof quotes.$inferInsert;
export type Lead = typeof leads.$inferSelect;
export type NewLead = typeof leads.$inferInsert;
export type Activity = typeof activities.$inferSelect;
export type NewActivity = typeof activities.$inferInsert;
export type Reminder = typeof reminders.$inferSelect;
export type NewReminder = typeof reminders.$inferInsert;
export type ClientTranscript = typeof clientTranscripts.$inferSelect;
export type NewClientTranscript = typeof clientTranscripts.$inferInsert;
export type Proposal = typeof proposals.$inferSelect;
export type NewProposal = typeof proposals.$inferInsert;