import {
  index,
  integer,
  jsonb,
  pgTable,
  primaryKey,
  text,
  timestamp,
  uniqueIndex,
  uuid,
} from 'drizzle-orm/pg-core';
import { users } from './identity';

export const hubspotConnections = pgTable(
  'hubspot_connections',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    portalId: text('portal_id').notNull(),
    displayName: text('display_name'),
    status: text('status').notNull().default('active'),
    encryptedAccessToken: text('encrypted_access_token').notNull(),
    encryptedRefreshToken: text('encrypted_refresh_token').notNull(),
    accessTokenExpiresAt: timestamp('access_token_expires_at', { withTimezone: true }).notNull(),
    grantedScopes: text('granted_scopes').array().notNull(),
    connectedByUserId: uuid('connected_by_user_id').references(() => users.id, {
      onDelete: 'set null',
    }),
    installedAt: timestamp('installed_at', { withTimezone: true }).notNull().defaultNow(),
    refreshedAt: timestamp('refreshed_at', { withTimezone: true }),
    disconnectedAt: timestamp('disconnected_at', { withTimezone: true }),
    lastError: text('last_error'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    uniqueIndex('hubspot_connections_portal_unique').on(table.portalId),
    index('hubspot_connections_status_idx').on(table.status),
  ],
);

export const hubspotOauthStates = pgTable(
  'hubspot_oauth_states',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    nonceHash: text('nonce_hash').notNull(),
    requestedByUserId: uuid('requested_by_user_id').notNull().references(() => users.id, {
      onDelete: 'cascade',
    }),
    returnPath: text('return_path').notNull(),
    expiresAt: timestamp('expires_at', { withTimezone: true }).notNull(),
    consumedAt: timestamp('consumed_at', { withTimezone: true }),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    uniqueIndex('hubspot_oauth_states_nonce_unique').on(table.nonceHash),
    index('hubspot_oauth_states_expiry_idx').on(table.expiresAt),
  ],
);

export const hubspotExternalRecords = pgTable(
  'hubspot_external_records',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    connectionId: uuid('connection_id').notNull().references(() => hubspotConnections.id, {
      onDelete: 'cascade',
    }),
    objectType: text('object_type').notNull(),
    externalId: text('external_id').notNull(),
    properties: jsonb('properties').$type<Record<string, string | null>>().notNull(),
    archivedAt: timestamp('archived_at', { withTimezone: true }),
    externalCreatedAt: timestamp('external_created_at', { withTimezone: true }).notNull(),
    externalUpdatedAt: timestamp('external_updated_at', { withTimezone: true }).notNull(),
    fetchedAt: timestamp('fetched_at', { withTimezone: true }).notNull(),
    contentHash: text('content_hash').notNull(),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [
    uniqueIndex('hubspot_external_records_identity_unique').on(
      table.connectionId,
      table.objectType,
      table.externalId,
    ),
    index('hubspot_external_records_updated_idx').on(
      table.connectionId,
      table.objectType,
      table.externalUpdatedAt,
    ),
  ],
);

export const hubspotExternalLinks = pgTable(
  'hubspot_external_links',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    connectionId: uuid('connection_id').notNull().references(() => hubspotConnections.id, {
      onDelete: 'cascade',
    }),
    externalObjectType: text('external_object_type').notNull(),
    externalId: text('external_id').notNull(),
    localEntity: text('local_entity').notNull(),
    localRecordId: uuid('local_record_id').notNull(),
    linkedByUserId: uuid('linked_by_user_id').references(() => users.id, {
      onDelete: 'set null',
    }),
    linkedAt: timestamp('linked_at', { withTimezone: true }).notNull().defaultNow(),
    unlinkedAt: timestamp('unlinked_at', { withTimezone: true }),
  },
  (table) => [
    uniqueIndex('hubspot_external_links_external_unique').on(
      table.connectionId,
      table.externalObjectType,
      table.externalId,
    ),
    index('hubspot_external_links_local_idx').on(
      table.connectionId,
      table.localEntity,
      table.localRecordId,
    ),
  ],
);

export const hubspotSyncCursors = pgTable(
  'hubspot_sync_cursors',
  {
    connectionId: uuid('connection_id').notNull().references(() => hubspotConnections.id, {
      onDelete: 'cascade',
    }),
    objectType: text('object_type').notNull(),
    phase: text('phase').notNull().default('initial'),
    after: text('after'),
    pageStartedAt: timestamp('page_started_at', { withTimezone: true }),
    lastCompletedAt: timestamp('last_completed_at', { withTimezone: true }),
    lastError: text('last_error'),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
  },
  (table) => [primaryKey({ columns: [table.connectionId, table.objectType] })],
);

export const hubspotWebhookEvents = pgTable(
  'hubspot_webhook_events',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    connectionId: uuid('connection_id').references(() => hubspotConnections.id, {
      onDelete: 'set null',
    }),
    portalId: text('portal_id').notNull(),
    appId: text('app_id').notNull(),
    eventId: text('event_id').notNull(),
    eventType: text('event_type').notNull(),
    objectId: text('object_id').notNull(),
    occurredAt: timestamp('occurred_at', { withTimezone: true }).notNull(),
    dedupeKey: text('dedupe_key').notNull(),
    rawBodyHash: text('raw_body_hash').notNull(),
    payload: jsonb('payload').$type<Record<string, unknown>>().notNull(),
    status: text('status').notNull().default('pending'),
    attempts: integer('attempts').notNull().default(0),
    lastError: text('last_error'),
    receivedAt: timestamp('received_at', { withTimezone: true }).notNull().defaultNow(),
    processedAt: timestamp('processed_at', { withTimezone: true }),
  },
  (table) => [
    uniqueIndex('hubspot_webhook_events_dedupe_unique').on(table.dedupeKey),
    index('hubspot_webhook_events_pending_idx').on(table.status, table.receivedAt),
    index('hubspot_webhook_events_portal_idx').on(table.portalId, table.occurredAt),
  ],
);

export const hubspotJobs = pgTable(
  'hubspot_jobs',
  {
    id: uuid('id').primaryKey().defaultRandom(),
    connectionId: uuid('connection_id').notNull().references(() => hubspotConnections.id, {
      onDelete: 'cascade',
    }),
    kind: text('kind').notNull(),
    objectType: text('object_type'),
    payload: jsonb('payload').$type<Record<string, unknown>>().notNull().default({}),
    status: text('status').notNull().default('pending'),
    attempts: integer('attempts').notNull().default(0),
    runAfter: timestamp('run_after', { withTimezone: true }).notNull().defaultNow(),
    lockedAt: timestamp('locked_at', { withTimezone: true }),
    lockedBy: text('locked_by'),
    lastError: text('last_error'),
    createdAt: timestamp('created_at', { withTimezone: true }).notNull().defaultNow(),
    updatedAt: timestamp('updated_at', { withTimezone: true }).notNull().defaultNow(),
    completedAt: timestamp('completed_at', { withTimezone: true }),
  },
  (table) => [
    index('hubspot_jobs_claim_idx').on(table.status, table.runAfter),
    index('hubspot_jobs_connection_idx').on(table.connectionId, table.createdAt),
  ],
);

export type HubSpotConnection = typeof hubspotConnections.$inferSelect;
export type HubSpotExternalRecord = typeof hubspotExternalRecords.$inferSelect;
