import * as admin from 'firebase-admin'

// RevenueCat event types we care about.
type RevenueCatEventType =
  | 'INITIAL_PURCHASE'
  | 'RENEWAL'
  | 'PRODUCT_CHANGE'
  | 'TRANSFER'
  | 'UNCANCELLATION'
  | 'EXPIRATION'
  | 'CANCELLATION'
  | 'BILLING_ISSUE'
  | 'SUBSCRIBER_ALIAS'

export interface EntitlementEvent {
  id: string
  type: RevenueCatEventType
  app_user_id: string
  product_id: string
  period_type?: 'normal' | 'trial' | 'intro'
  expiration_at_ms?: number
  is_family_share?: boolean
  entitlement_id?: string
  entitlement_ids?: string[]
  store?: 'app_store' | 'play_store' | 'mac_store' | 'stripe' | 'unknown'
  environment?: 'SANDBOX' | 'PRODUCTION'
}

export interface EntitlementState {
  premium: boolean
  expiresAt: admin.firestore.Timestamp | null
  updatedAt: admin.firestore.Timestamp
}

// Events that should grant or keep premium access active.
export const PREMIUM_ACTIVE_TYPES: Set<RevenueCatEventType> = new Set([
  'INITIAL_PURCHASE',
  'RENEWAL',
  'PRODUCT_CHANGE',
  'TRANSFER',
  'UNCANCELLATION',
])

// Events that remove premium access.
export const PREMIUM_REVOKED_TYPES: Set<RevenueCatEventType> = new Set([
  'EXPIRATION',
  'CANCELLATION',
  'BILLING_ISSUE',
  'SUBSCRIBER_ALIAS',
])

// Premium entitlement identifier used by the app.
const PREMIUM_ENTITLEMENT_ID = 'closer_premium'

function getDb(): admin.firestore.Firestore {
  return admin.firestore()
}

function entitlementsRef(userId: string) {
  return getDb().collection('users').doc(userId).collection('entitlements').doc('premium')
}

function now(): admin.firestore.Timestamp {
  return admin.firestore.Timestamp.now()
}

export function isPremiumEntitlement(event: EntitlementEvent): boolean {
  const entitlementId = event.entitlement_id
  const entitlementIds = event.entitlement_ids ?? []
  if (entitlementId === PREMIUM_ENTITLEMENT_ID) return true
  if (entitlementIds.includes(PREMIUM_ENTITLEMENT_ID)) return true
  return false
}

/**
 * Apply a RevenueCat entitlement event to Firestore.
 * Writes state to users/{userId}/entitlements.
 */
export async function applyEntitlementEvent(event: EntitlementEvent): Promise<void> {
  const { type, app_user_id: userId, id: eventId, product_id: productId } = event

  // Idempotency: create a processed event marker; if it exists, skip.
  const eventRef = getDb().collection('entitlement_events').doc(eventId)
  try {
    await eventRef.create({ processedAt: now() })
  } catch (err: any) {
    if (err?.code === 6 || err?.message?.includes('ALREADY_EXISTS')) {
      console.log(`[entitlement] skipping duplicate event: ${eventId}`)
      return
    }
    throw err
  }

  if (!isPremiumEntitlement(event)) {
    console.log(`[entitlement] ignored event for non-premium entitlement: ${eventId}`)
    return
  }

  const ref = entitlementsRef(userId)

  if (PREMIUM_ACTIVE_TYPES.has(type)) {
    const expiresAt = event.expiration_at_ms
      ? admin.firestore.Timestamp.fromMillis(event.expiration_at_ms)
      : null

    await ref.set({
      premium: true,
      expiresAt,
      updatedAt: now(),
      productId,
      eventType: type,
    } as EntitlementState & { productId: string; eventType: RevenueCatEventType })

    console.log(`[entitlement] premium=true for ${userId} (${type})`)
    return
  }

  if (PREMIUM_REVOKED_TYPES.has(type)) {
    await ref.set({
      premium: false,
      expiresAt: null,
      updatedAt: now(),
      productId,
      eventType: type,
    } as EntitlementState & { productId: string; eventType: RevenueCatEventType })

    console.log(`[entitlement] premium=false for ${userId} (${type})`)
    return
  }

  console.log(`[entitlement] ignored event type: ${type}`)
}

/**
 * Recompute and rewrite the entitlement document for a user.
 *
 * In production this should query RevenueCat; for now it ensures the
 * Firestore document is consistent and reflects the latest stored values.
 */
export async function applyEntitlementSync(userId: string): Promise<EntitlementState> {
  const ref = entitlementsRef(userId)
  const snap = await ref.get()
  const data = snap.data() as Partial<EntitlementState> | undefined

  const updatedAt = now()

  let premium = false
  let expiresAt: admin.firestore.Timestamp | null = null

  if (data?.premium === true) {
    const storedExpiresAt = data.expiresAt ?? null
    if (storedExpiresAt instanceof admin.firestore.Timestamp) {
      premium = storedExpiresAt.toMillis() > Date.now()
      expiresAt = storedExpiresAt
    } else {
      // No expiration means a currently active, non-expiring entitlement.
      premium = true
    }
  }

  const state: EntitlementState = {
    premium,
    expiresAt: premium ? expiresAt : null,
    updatedAt,
  }

  await ref.set(state, { merge: true })
  return state
}
