import {
  boolean,
  index,
  integer,
  jsonb,
  numeric,
  pgEnum,
  pgTable,
  text,
  timestamp,
  unique,
  uuid,
} from "drizzle-orm/pg-core";

// ─── Enums ────────────────────────────────────────────────────────────────────

export const appointmentStatusEnum = pgEnum("appointment_status", [
  "scheduled",
  "confirmed",
  "in_progress",
  "completed",
  "cancelled",
  "no_show",
]);

export const staffRoleEnum = pgEnum("staff_role", [
  "groomer",
  "receptionist",
  "manager",
]);

export const invoiceStatusEnum = pgEnum("invoice_status", [
  "draft",
  "pending",
  "paid",
  "void",
]);

export const paymentMethodEnum = pgEnum("payment_method", [
  "cash",
  "card",
  "check",
  "other",
]);

export const clientStatusEnum = pgEnum("client_status", [
  "active",
  "disabled",
]);

// ─── Better-Auth Tables ──────────────────────────────────────────────────────

export const user = pgTable("user", {
  id: text("id").primaryKey(),
  name: text("name").notNull(),
  email: text("email").notNull().unique(),
  emailVerified: boolean("email_verified").notNull().default(false),
  image: text("image"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const session = pgTable("session", {
  id: text("id").primaryKey(),
  expiresAt: timestamp("expires_at").notNull(),
  token: text("token").notNull().unique(),
  ipAddress: text("ip_address"),
  userAgent: text("user_agent"),
  userId: text("user_id")
    .notNull()
    .references(() => user.id, { onDelete: "cascade" }),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const account = pgTable("account", {
  id: text("id").primaryKey(),
  accountId: text("account_id").notNull(),
  providerId: text("provider_id").notNull(),
  userId: text("user_id")
    .notNull()
    .references(() => user.id, { onDelete: "cascade" }),
  accessToken: text("access_token"),
  refreshToken: text("refresh_token"),
  idToken: text("id_token"),
  accessTokenExpiresAt: timestamp("access_token_expires_at"),
  refreshTokenExpiresAt: timestamp("refresh_token_expires_at"),
  scope: text("scope"),
  password: text("password"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const verification = pgTable("verification", {
  id: text("id").primaryKey(),
  identifier: text("identifier").notNull(),
  value: text("value").notNull(),
  expiresAt: timestamp("expires_at").notNull(),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

// ─── Tables ───────────────────────────────────────────────────────────────────

export const clients = pgTable(
  "clients",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    name: text("name").notNull(),
    email: text("email").notNull(),
    phone: text("phone"),
    address: text("address"),
    notes: text("notes"),
    emailOptOut: boolean("email_opt_out").notNull().default(false),
    smsOptIn: boolean("sms_opt_in").notNull().default(false),
    smsConsentDate: timestamp("sms_consent_date"),
    smsOptOutDate: timestamp("sms_opt_out_date"),
    smsConsentText: text("sms_consent_text"),
    stripeCustomerId: text("stripe_customer_id"),
    status: clientStatusEnum("status").notNull().default("active"),
    disabledAt: timestamp("disabled_at"),
    createdAt: timestamp("created_at").notNull().defaultNow(),
    updatedAt: timestamp("updated_at").notNull().defaultNow(),
  },
  (t) => [index("idx_clients_email").on(t.email)]
);

export const pets = pgTable(
  "pets",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    clientId: uuid("client_id")
      .notNull()
      .references(() => clients.id, { onDelete: "cascade" }),
    name: text("name").notNull(),
    species: text("species").notNull(),
    breed: text("breed"),
    weightKg: numeric("weight_kg", { precision: 5, scale: 2 }),
    dateOfBirth: timestamp("date_of_birth"),
    healthAlerts: text("health_alerts"),
    groomingNotes: text("grooming_notes"),
    cutStyle: text("cut_style"),
    shampooPreference: text("shampoo_preference"),
    specialCareNotes: text("special_care_notes"),
    customFields: jsonb("custom_fields").$type<Record<string, string>>().notNull().default({}),
    photoKey: text("photo_key"),
    photoUploadedAt: timestamp("photo_uploaded_at"),
    image: text("image"),
    createdAt: timestamp("created_at").notNull().defaultNow(),
    updatedAt: timestamp("updated_at").notNull().defaultNow(),
  },
  (t) => [index("idx_pets_client_id").on(t.clientId)]
);

export const services = pgTable("services", {
  id: uuid("id").primaryKey().defaultRandom(),
  name: text("name").notNull().unique(),
  description: text("description"),
  basePriceCents: integer("base_price_cents").notNull(),
  durationMinutes: integer("duration_minutes").notNull(),
  active: boolean("active").notNull().default(true),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const staff = pgTable("staff", {
  id: uuid("id").primaryKey().defaultRandom(),
  name: text("name").notNull(),
  email: text("email").notNull().unique(),
  // oidcSub links to the Authentik OIDC subject claim
  oidcSub: text("oidc_sub").unique(),
  // Better-Auth user ID — links staff business record to auth identity
  userId: text("user_id").references(() => user.id, { onDelete: "set null" }),
  role: staffRoleEnum("role").notNull().default("groomer"),
  // Super users bypass appointment-booking restrictions and access admin panels
  isSuperUser: boolean("is_super_user").notNull().default(false),
  active: boolean("active").notNull().default(true),
  // Token for iCal calendar feed subscription (no auth required)
  icalToken: text("ical_token").unique(),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const recurringSeries = pgTable("recurring_series", {
  id: uuid("id").primaryKey().defaultRandom(),
  // How many weeks between each appointment in the series
  frequencyWeeks: integer("frequency_weeks").notNull(),
  createdAt: timestamp("created_at").notNull().defaultNow(),
});

// appointmentGroups links multiple appointments from the same client visit.
// Each pet in the group gets its own appointment row with its own groomer.
export const appointmentGroups = pgTable("appointment_groups", {
  id: uuid("id").primaryKey().defaultRandom(),
  clientId: uuid("client_id")
    .notNull()
    .references(() => clients.id, { onDelete: "restrict" }),
  notes: text("notes"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const appointments = pgTable(
  "appointments",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    clientId: uuid("client_id")
      .notNull()
      .references(() => clients.id, { onDelete: "restrict" }),
    petId: uuid("pet_id")
      .notNull()
      .references(() => pets.id, { onDelete: "restrict" }),
    serviceId: uuid("service_id")
      .notNull()
      .references(() => services.id, { onDelete: "restrict" }),
    staffId: uuid("staff_id").references(() => staff.id, {
      onDelete: "set null",
    }),
    // Optional secondary staff (bather/assistant) for tip-split tracking
    batherStaffId: uuid("bather_staff_id").references(() => staff.id, {
      onDelete: "set null",
    }),
    status: appointmentStatusEnum("status").notNull().default("scheduled"),
    startTime: timestamp("start_time").notNull(),
    endTime: timestamp("end_time").notNull(),
    notes: text("notes"),
    // Override price at time of booking (null = use service base price)
    priceCents: integer("price_cents"),
    // Recurring series support
    seriesId: uuid("series_id").references(() => recurringSeries.id, {
      onDelete: "set null",
    }),
    seriesIndex: integer("series_index"),
    // Multi-pet group booking: links this appointment to others in the same visit
    groupId: uuid("group_id").references(() => appointmentGroups.id, {
      onDelete: "set null",
    }),
    // Customer confirmation/cancellation tracking
    // Values: "pending" | "confirmed" | "cancelled"
    confirmationStatus: text("confirmation_status").notNull().default("pending"),
    confirmedAt: timestamp("confirmed_at"),
    cancelledAt: timestamp("cancelled_at"),
    // Token for tokenized email confirm/cancel links (no auth required)
    confirmationToken: text("confirmation_token").unique(),
    // Customer-provided note visible to groomer (500 char max, editable until appointment starts)
    customerNotes: text("customer_notes"),
    createdAt: timestamp("created_at").notNull().defaultNow(),
    updatedAt: timestamp("updated_at").notNull().defaultNow(),
  },
  (t) => [
    index("idx_appointments_client_id").on(t.clientId),
    index("idx_appointments_staff_id").on(t.staffId),
    index("idx_appointments_start_time").on(t.startTime),
    index("idx_appointments_status").on(t.status),
  ]
);

export const invoices = pgTable(
  "invoices",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    appointmentId: uuid("appointment_id").references(() => appointments.id, {
      onDelete: "restrict",
    }),
    clientId: uuid("client_id")
      .notNull()
      .references(() => clients.id, { onDelete: "restrict" }),
    subtotalCents: integer("subtotal_cents").notNull(),
    taxCents: integer("tax_cents").notNull().default(0),
    tipCents: integer("tip_cents").notNull().default(0),
    totalCents: integer("total_cents").notNull(),
    status: invoiceStatusEnum("status").notNull().default("draft"),
    paymentMethod: paymentMethodEnum("payment_method"),
    paidAt: timestamp("paid_at"),
    stripePaymentIntentId: text("stripe_payment_intent_id"),
    stripeRefundId: text("stripe_refund_id"),
    paymentFailureReason: text("payment_failure_reason"),
    notes: text("notes"),
    createdAt: timestamp("created_at").notNull().defaultNow(),
    updatedAt: timestamp("updated_at").notNull().defaultNow(),
  },
  (t) => [
    index("idx_invoices_client_id").on(t.clientId),
    index("idx_invoices_status").on(t.status),
    index("idx_invoices_created_at").on(t.createdAt),
    index("idx_invoices_stripe_payment_intent_id").on(t.stripePaymentIntentId),
  ]
);

export const invoiceLineItems = pgTable(
  "invoice_line_items",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    invoiceId: uuid("invoice_id")
      .notNull()
      .references(() => invoices.id, { onDelete: "cascade" }),
    description: text("description").notNull(),
    quantity: integer("quantity").notNull().default(1),
    unitPriceCents: integer("unit_price_cents").notNull(),
    totalCents: integer("total_cents").notNull(),
    createdAt: timestamp("created_at").notNull().defaultNow(),
  },
  (t) => [index("idx_invoice_line_items_invoice_id").on(t.invoiceId)]
);

// Per-staff tip allocation calculated when an invoice is paid.
// staff_name is snapshotted at calculation time so reports remain accurate if staff is deleted.
export const invoiceTipSplits = pgTable(
  "invoice_tip_splits",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    invoiceId: uuid("invoice_id")
      .notNull()
      .references(() => invoices.id, { onDelete: "cascade" }),
    staffId: uuid("staff_id").references(() => staff.id, { onDelete: "set null" }),
    staffName: text("staff_name").notNull(),
    sharePct: numeric("share_pct", { precision: 5, scale: 2 }).notNull(),
    shareCents: integer("share_cents").notNull(),
    createdAt: timestamp("created_at").notNull().defaultNow(),
  },
  (t) => [index("idx_invoice_tip_splits_invoice_id").on(t.invoiceId)]
);

// Refund records with idempotency key support
export const refunds = pgTable(
  "refunds",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    invoiceId: uuid("invoice_id")
      .notNull()
      .references(() => invoices.id, { onDelete: "restrict" }),
    stripeRefundId: text("stripe_refund_id").notNull(),
    idempotencyKey: text("idempotency_key").unique(),
    amountCents: integer("amount_cents"),
    createdAt: timestamp("created_at").notNull().defaultNow(),
  },
  (t) => [
    index("idx_refunds_invoice_id").on(t.invoiceId),
    index("idx_refunds_idempotency_key").on(t.idempotencyKey),
  ]
);

// Tracks which reminder emails have been sent per appointment (prevents duplicates).
// reminder_type values: "confirmation", "24h", "2h"
// channel values: "email", "sms"
export const reminderLogs = pgTable(
  "reminder_logs",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    appointmentId: uuid("appointment_id")
      .notNull()
      .references(() => appointments.id, { onDelete: "cascade" }),
    // "confirmation" | "24h" | "2h"
    reminderType: text("reminder_type").notNull(),
    // "email" | "sms"
    channel: text("channel").notNull().default("email"),
    sentAt: timestamp("sent_at").notNull().defaultNow(),
  },
  (t) => [unique().on(t.appointmentId, t.reminderType, t.channel)]
);

// ─── Impersonation ──────────────────────────────────────────────────────────

export const impersonationSessionStatusEnum = pgEnum(
  "impersonation_session_status",
  ["active", "ended", "expired"]
);

export const impersonationSessions = pgTable(
  "impersonation_sessions",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    staffId: uuid("staff_id")
      .notNull()
      .references(() => staff.id, { onDelete: "restrict" }),
    clientId: uuid("client_id")
      .notNull()
      .references(() => clients.id, { onDelete: "restrict" }),
    reason: text("reason"),
    status: impersonationSessionStatusEnum("status")
      .notNull()
      .default("active"),
    startedAt: timestamp("started_at").notNull().defaultNow(),
    endedAt: timestamp("ended_at"),
    expiresAt: timestamp("expires_at").notNull(),
    createdAt: timestamp("created_at").notNull().defaultNow(),
  },
  (t) => [
    index("impersonation_sessions_staff_id_status_idx").on(t.staffId, t.status),
    index("impersonation_sessions_client_id_idx").on(t.clientId),
  ]
);

export const impersonationAuditLogs = pgTable(
  "impersonation_audit_logs",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    sessionId: uuid("session_id")
      .notNull()
      .references(() => impersonationSessions.id, { onDelete: "cascade" }),
    action: text("action").notNull(),
    pageVisited: text("page_visited"),
    metadata: jsonb("metadata").$type<Record<string, unknown>>(),
    createdAt: timestamp("created_at").notNull().defaultNow(),
  },
  (t) => [index("impersonation_audit_logs_session_id_idx").on(t.sessionId)]
);

export const businessSettings = pgTable("business_settings", {
  id: uuid("id").primaryKey().defaultRandom(),
  businessName: text("business_name").notNull().default("GroomBook"),
  logoBase64: text("logo_base64"),
  logoMimeType: text("logo_mime_type"),
  logoKey: text("logo_key"),
  primaryColor: text("primary_color").notNull().default("#4f8a6f"),
  accentColor: text("accent_color").notNull().default("#8b7355"),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});

export const groomingVisitLogs = pgTable("grooming_visit_logs", {
  id: uuid("id").primaryKey().defaultRandom(),
  petId: uuid("pet_id")
    .notNull()
    .references(() => pets.id, { onDelete: "cascade" }),
  appointmentId: uuid("appointment_id").references(() => appointments.id, {
    onDelete: "set null",
  }),
  staffId: uuid("staff_id").references(() => staff.id, {
    onDelete: "set null",
  }),
  cutStyle: text("cut_style"),
  productsUsed: text("products_used"),
  notes: text("notes"),
  groomedAt: timestamp("groomed_at").notNull().defaultNow(),
  createdAt: timestamp("created_at").notNull().defaultNow(),
});

export const waitlistStatusEnum = pgEnum("waitlist_status", [
  "active",
  "notified",
  "expired",
  "cancelled",
]);

export const waitlistEntries = pgTable(
  "waitlist_entries",
  {
    id: uuid("id").primaryKey().defaultRandom(),
    clientId: uuid("client_id")
      .notNull()
      .references(() => clients.id, { onDelete: "cascade" }),
    petId: uuid("pet_id")
      .notNull()
      .references(() => pets.id, { onDelete: "cascade" }),
    serviceId: uuid("service_id")
      .notNull()
      .references(() => services.id, { onDelete: "cascade" }),
    preferredDate: text("preferred_date").notNull(),
    preferredTime: text("preferred_time").notNull(),
    status: waitlistStatusEnum("status").notNull().default("active"),
    notifiedAt: timestamp("notified_at"),
    expiresAt: timestamp("expires_at"),
    createdAt: timestamp("created_at").notNull().defaultNow(),
    updatedAt: timestamp("updated_at").notNull().defaultNow(),
  },
  (t) => [
    index("idx_waitlist_client_id").on(t.clientId),
    index("idx_waitlist_preferred_date").on(t.preferredDate),
    index("idx_waitlist_status").on(t.status),
  ]
);

// ─── Auth Provider Config ──────────────────────────────────────────────────

export const authProviderConfig = pgTable("auth_provider_config", {
  id: uuid("id").primaryKey().defaultRandom(),
  providerId: text("provider_id").notNull().unique(), // e.g. "authentik", "okta", "entra-id"
  displayName: text("display_name").notNull(), // shown on login button
  issuerUrl: text("issuer_url").notNull(), // OIDC issuer/discovery URL
  internalBaseUrl: text("internal_base_url"), // for hairpin NAT / K8s internal routing
  clientId: text("client_id").notNull(),
  clientSecret: text("client_secret").notNull(), // AES-256-GCM encrypted using BETTER_AUTH_SECRET
  scopes: text("scopes").notNull().default("openid profile email"),
  enabled: boolean("enabled").notNull().default(true),
  createdAt: timestamp("created_at").notNull().defaultNow(),
  updatedAt: timestamp("updated_at").notNull().defaultNow(),
});
