// ---------------------------------------------------------------------------
// Deal ownership axis — derived from activity_log (Pattern A, approved).
//
// Ownership reflects who owes the next move, not a stored column.
// Closed deals always return null — ownership is meaningless once won/lost.
// ---------------------------------------------------------------------------

export type DealOwnership = 'us' | 'them' | null

// Inbound events: lead acted, ball is in our court.
const INBOUND_EVENT_TYPES = ['reply_received'] as const

// Outbound events: we acted, ball is in their court.
const OUTBOUND_EVENT_TYPES = [
  'reply_sent_to_lead',
  'booking_nudge_sent',
  'reminder_sent',
  'rebook_sent',
  'followup_email_sent',
  'reply_followup_sent',
  'lead_deferred_next_step'
] as const

type InboundEventType = (typeof INBOUND_EVENT_TYPES)[number]
type OutboundEventType = (typeof OUTBOUND_EVENT_TYPES)[number]

const INBOUND_SET = new Set<string>(INBOUND_EVENT_TYPES)
const OUTBOUND_SET = new Set<string>(OUTBOUND_EVENT_TYPES)

interface DealOwnershipInput {
  state_key: string | null
  activity_log: unknown
}

/**
 * Derives who owes the next move from the activity log.
 *
 * - `'us'`   — the lead replied last; we owe a response.
 * - `'them'` — we sent something last; waiting on their reply.
 * - `null`   — closed deal, or no inbound/outbound events present.
 *
 * Timestamp resolution matches the canonical pattern in crm-priority.ts:
 * COALESCE across `timestamp ?? occurredAt ?? createdAt ?? updatedAt ?? sentAt`.
 */
export function getDealOwnership(deal: DealOwnershipInput): DealOwnership {
  if (deal.state_key === 'closed_won' || deal.state_key === 'closed_lost') {
    return null
  }

  if (!Array.isArray(deal.activity_log)) return null

  let latestInboundMs: number | null = null
  let latestOutboundMs: number | null = null

  for (const entry of deal.activity_log) {
    if (!entry || typeof entry !== 'object' || Array.isArray(entry)) continue

    const record = entry as Record<string, unknown>
    const type = typeof record.type === 'string' ? record.type : null
    if (!type) continue

    const isInbound = INBOUND_SET.has(type)
    const isOutbound = OUTBOUND_SET.has(type)
    if (!isInbound && !isOutbound) continue

    const occurredAt = resolveTimestamp(record)
    if (occurredAt === null) continue

    if (isInbound && (latestInboundMs === null || occurredAt > latestInboundMs)) {
      latestInboundMs = occurredAt
    }

    if (isOutbound && (latestOutboundMs === null || occurredAt > latestOutboundMs)) {
      latestOutboundMs = occurredAt
    }
  }

  if (latestInboundMs === null && latestOutboundMs === null) return null

  // Tie-break: outbound wins ("after we send, ball is in their court")
  if (latestOutboundMs !== null && (latestInboundMs === null || latestOutboundMs >= latestInboundMs)) {
    return 'them'
  }

  return 'us'
}

// ---------------------------------------------------------------------------
// Internal helpers
// ---------------------------------------------------------------------------

/**
 * COALESCE timestamp fields in the same order as getParsedActivities in
 * crm-priority.ts: timestamp → occurredAt → createdAt → updatedAt → sentAt.
 * Returns milliseconds since epoch, or null if no valid date found.
 */
function resolveTimestamp(record: Record<string, unknown>): number | null {
  return (
    parseMs(record.timestamp) ??
    parseMs(record.occurredAt) ??
    parseMs(record.createdAt) ??
    parseMs(record.updatedAt) ??
    parseMs(record.sentAt) ??
    null
  )
}

function parseMs(value: unknown): number | null {
  if (value instanceof Date) {
    const ms = value.getTime()
    return Number.isNaN(ms) ? null : ms
  }
  if (typeof value !== 'string') return null
  const ms = new Date(value).getTime()
  return Number.isNaN(ms) ? null : ms
}

// Re-export event type lists for consumers that want to introspect classification.
export { INBOUND_EVENT_TYPES, OUTBOUND_EVENT_TYPES }
export type { InboundEventType, OutboundEventType }
