/**
 * Marketplace subscription — contract/PO-first self-service subscribe + entitlement grants.
 */
import fs from 'fs'
import path from 'path'
import { getDb } from '../db/index.js'
import { logger } from '../lib/logger.js'
import { catalogService } from './catalog.js'
import { operatingModelService } from './operating-model.js'
import { identityService } from './identity.js'
import type { Context } from '../types/context.js'
import type { Entitlement, ServiceSubscription } from '../types/operating-model.js'

interface RegistryProduct {
  productSlug: string
  entitlementKeys: string[]
  fulfillmentMode?: string
  tierEntitlements?: Record<string, string>
  displayName?: string
}

type FulfillmentMode = 'self_service' | 'operator_provisioned' | 'request_only'

function loadRegistryProducts(): RegistryProduct[] {
  const candidates = [
    process.env.MARKETPLACE_ENTITLEMENT_REGISTRY_PATH,
    path.join(process.cwd(), 'config/marketplace-entitlement-registry.v1.json'),
  ].filter(Boolean) as string[]

  for (const candidate of candidates) {
    if (fs.existsSync(candidate)) {
      const parsed = JSON.parse(fs.readFileSync(candidate, 'utf8')) as { products?: RegistryProduct[] }
      return parsed.products || []
    }
  }
  return []
}

function subscriptionStatusForMode(mode: FulfillmentMode): 'ACTIVE' | 'PENDING' | 'REQUEST_ONLY' {
  if (mode === 'self_service') return 'ACTIVE'
  if (mode === 'request_only') return 'REQUEST_ONLY'
  return 'PENDING'
}

class MarketplaceSubscriptionService {
  getRegistryEntry(slug: string): RegistryProduct | undefined {
    return loadRegistryProducts().find((entry) => entry.productSlug === slug)
  }

  resolveEntitlementKeys(
    slug: string,
    productMetadata?: Record<string, unknown>,
    sku?: string
  ): string[] {
    const entry = this.getRegistryEntry(slug)
    if (sku && entry?.tierEntitlements?.[sku]) {
      const tierKey = entry.tierEntitlements[sku]
      const base = entry.entitlementKeys.includes('AEGIS_VAULT_ENTITLED')
        ? ['AEGIS_VAULT_ENTITLED', tierKey]
        : [tierKey]
      return [...new Set(base)]
    }
    if (entry?.entitlementKeys?.length) {
      return modePrimaryKeys(entry.entitlementKeys)
    }
    const flag = productMetadata?.entitlementFeatureFlag
    if (typeof flag === 'string' && flag.trim()) {
      return [flag.trim()]
    }
    return [`${slug.replace(/-/g, '_').toUpperCase()}_ENTITLED`]
  }

  async getTenantEntitlements(tenantId: string): Promise<Entitlement[]> {
    return operatingModelService.listEntitlements({ tenantId })
  }

  async getTenantSubscriptions(tenantId: string): Promise<ServiceSubscription[]> {
    return operatingModelService.listSubscriptions({ tenantId })
  }

  async subscribeToProduct(
    context: Context,
    input: { productSlug: string; sku?: string; syncKeycloak?: boolean }
  ): Promise<{
    subscription: ServiceSubscription
    entitlements: Entitlement[]
    productSlug: string
    fulfillmentMode: FulfillmentMode
    keycloakSynced: boolean
  }> {
    const tenantId = context.tenantContext?.tenantId
    const userEmail = context.tenantContext?.email
    if (!tenantId) {
      throw new Error('Tenant membership required to subscribe')
    }

    const product = await catalogService.getProductBySlug(context, input.productSlug)
    if (!product || product.status !== 'PUBLISHED') {
      throw new Error(`Product not found or not published: ${input.productSlug}`)
    }

    const registryEntry = this.getRegistryEntry(input.productSlug)
    const fulfillmentMode = (registryEntry?.fulfillmentMode ||
      (product.metadata?.fulfillmentMode as string) ||
      'operator_provisioned') as FulfillmentMode
    const status = subscriptionStatusForMode(fulfillmentMode)
    const entitlementKeys = this.resolveEntitlementKeys(
      input.productSlug,
      product.metadata,
      input.sku
    )

    const bootstrap = await operatingModelService.bootstrapClientForTenant(tenantId)
    const db = getDb()

    const existing = await db.query(
      `SELECT * FROM service_subscriptions
       WHERE tenant_id = $1 AND offer_code = $2
       ORDER BY created_at ASC LIMIT 1`,
      [tenantId, input.productSlug]
    )

    let subscriptionRow = existing.rows[0]
    if (!subscriptionRow) {
      const created = await db.query(
        `INSERT INTO service_subscriptions (
           client_id, tenant_id, offer_code, offer_name, offer_type,
           commercial_model, support_owner, fulfillment_mode, billing_mode,
           status, activated_at, metadata
         ) VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12)
         RETURNING *`,
        [
          bootstrap.client.id,
          tenantId,
          input.productSlug,
          product.name,
          'marketplace',
          'contract_po_first',
          'sankofa',
          fulfillmentMode,
          'manual',
          status,
          status === 'ACTIVE' ? new Date() : null,
          JSON.stringify({
            source: 'marketplaceSubscribe',
            productSlug: input.productSlug,
            sku: input.sku || null,
            registryDisplayName: registryEntry?.displayName || product.name,
          }),
        ]
      )
      subscriptionRow = created.rows[0]
    } else if (existing.rows[0].status === 'PENDING' && status === 'ACTIVE') {
      const updated = await db.query(
        `UPDATE service_subscriptions
         SET status = $1, activated_at = COALESCE(activated_at, NOW()), updated_at = NOW()
         WHERE id = $2
         RETURNING *`,
        [status, existing.rows[0].id]
      )
      subscriptionRow = updated.rows[0]
    }

    const entitlements: Entitlement[] = []
    for (const key of entitlementKeys) {
      const found = await db.query(
        `SELECT * FROM entitlements
         WHERE subscription_id = $1 AND entitlement_key = $2 LIMIT 1`,
        [subscriptionRow.id, key]
      )
      let row = found.rows[0]
      if (!row) {
        const createdEntitlement = await db.query(
          `INSERT INTO entitlements (subscription_id, tenant_id, entitlement_key, status, scope, metadata)
           VALUES ($1, $2, $3, $4, $5, $6)
           RETURNING *`,
          [
            subscriptionRow.id,
            tenantId,
            key,
            status === 'ACTIVE' ? 'ACTIVE' : status === 'REQUEST_ONLY' ? 'REQUEST_ONLY' : 'PENDING',
            JSON.stringify({ productSlug: input.productSlug, sku: input.sku || null }),
            JSON.stringify({ source: 'marketplaceSubscribe' }),
          ]
        )
        row = createdEntitlement.rows[0]
      }
      entitlements.push({
        id: row.id,
        subscriptionId: row.subscription_id,
        tenantId: row.tenant_id,
        entitlementKey: row.entitlement_key,
        status: row.status,
        scope: row.scope || {},
        metadata: row.metadata || {},
        createdAt: row.created_at,
        updatedAt: row.updated_at,
      })
    }

    let keycloakSynced = false
    const shouldSync =
      input.syncKeycloak !== false &&
      status === 'ACTIVE' &&
      process.env.MARKETPLACE_KEYCLOAK_SYNC !== '0'
    if (shouldSync && userEmail) {
      keycloakSynced = await identityService.mergeUserEntitlementAttributes(
        userEmail,
        entitlementKeys,
        true
      )
    }

    logger.info('Marketplace subscription created', {
      tenantId,
      productSlug: input.productSlug,
      subscriptionId: subscriptionRow.id,
      entitlementKeys,
      fulfillmentMode,
      keycloakSynced,
    })

    const subscription = (await operatingModelService.listSubscriptions({ tenantId })).find(
      (s) => s.id === subscriptionRow.id
    )!

    return {
      subscription,
      entitlements,
      productSlug: input.productSlug,
      fulfillmentMode,
      keycloakSynced,
    }
  }
}

function modePrimaryKeys(keys: string[]): string[] {
  if (keys.length <= 1) return keys
  const base = keys.find((k) => k.endsWith('_ENTITLED') && !k.includes('_ESSENTIALS') && !k.includes('_PRO') && !k.includes('_ENTERPRISE'))
  return base ? [base] : [keys[0]]
}

export const marketplaceSubscriptionService = new MarketplaceSubscriptionService()
