import type { FastifyInstance, FastifyReply, FastifyRequest } from 'fastify'
import { requireTenant } from '../middleware/tenant-auth.js'
import { marketplaceSubscriptionService } from '../services/marketplace-subscription.js'

const PRODUCT_SLUG = 'phoenix-openpayd-connector'
const ENTITLEMENT_KEY = 'OPENPAYD_CONNECTOR_ENTITLED'
const CONNECTOR_BASE =
  process.env.OPENPAYD_CONNECTOR_INTERNAL_URL || 'https://openpayd-connector.sankofa.nexus'

const OPERATOR_COMMANDS = new Set([
  'probeEnvironment',
  'rotateCredential',
  'setProductionMutatingGate',
  'suspendTenant',
  'offboardTenant',
  'exportComplianceEvidencePack'
])

const TENANT_COMMANDS = new Set([
  'getStatus',
  'syncPaymentAccounts',
  'getBeneficiaryRequiredDetails',
  'validateBeneficiary',
  'createLinkedClient',
  'createAccount',
  'createBankBeneficiary',
  'createPayout',
  'initiateOpenBankingPayment'
])

function tenantFromRequest(request: FastifyRequest, reply: FastifyReply) {
  const headerTenant = (request.headers['x-tenant-id'] as string | undefined)?.trim()
  if (headerTenant && request.tenantContext) {
    request.tenantContext = { ...request.tenantContext, tenantId: headerTenant }
  }
  return requireTenant(request, reply)
}

function isOperator(context: ReturnType<typeof tenantFromRequest>): boolean {
  const role = `${context.role || ''}`.toLowerCase()
  const tenantRole = `${context.tenantRole || ''}`.toLowerCase()
  return context.isSystemAdmin || role === 'admin' || tenantRole === 'tenant-admin' || tenantRole === 'admin'
}

async function entitlementState(tenantId: string) {
  const entitlements = await marketplaceSubscriptionService.getTenantEntitlements(tenantId)
  const row = entitlements.find((entitlement) => entitlement.entitlementKey === ENTITLEMENT_KEY)
  return {
    entitlement: row,
    entitled: Boolean(row && ['ACTIVE', 'PENDING', 'REQUEST_ONLY'].includes(row.status)),
    active: row?.status === 'ACTIVE'
  }
}

async function proxyConnector(command: string, body: Record<string, unknown>) {
  const res = await fetch(`${CONNECTOR_BASE.replace(/\/$/, '')}/v1/commands/${command}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body)
  })
  const data = await res.json().catch(() => ({}))
  return { status: res.status, data }
}

export async function registerOpenPaydConnectorRoutes(fastify: FastifyInstance) {
  fastify.get('/api/v1/openpayd/status', async (request, reply) => {
    const context = tenantFromRequest(request, reply)
    const tenantId = context.tenantId!
    const entitlements = await entitlementState(tenantId)
    if (!entitlements.entitled && !isOperator(context)) {
      return reply.code(403).send({ error: 'OpenPayd connector entitlement required', productSlug: PRODUCT_SLUG })
    }

    const environment = ((request.query as { environment?: string }).environment || 'sandbox') as string
    const proxied = await proxyConnector('getStatus', { tenantId, environment })
    return reply.code(proxied.status).send({
      productSlug: PRODUCT_SLUG,
      entitlementKey: ENTITLEMENT_KEY,
      entitlementStatus: entitlements.entitlement?.status || 'NONE',
      connector: proxied.data
    })
  })

  fastify.post('/api/v1/openpayd/commands/:command', async (request, reply) => {
    const context = tenantFromRequest(request, reply)
    const tenantId = context.tenantId!
    const command = (request.params as { command: string }).command
    const body = (request.body || {}) as Record<string, unknown>
    const entitlements = await entitlementState(tenantId)
    const operator = isOperator(context)

    if (!entitlements.entitled && !operator) {
      return reply.code(403).send({ error: 'OpenPayd connector entitlement required', productSlug: PRODUCT_SLUG })
    }
    if (OPERATOR_COMMANDS.has(command) && !operator) {
      return reply.code(403).send({ error: 'Operator role required for OpenPayd command', command })
    }
    if (!OPERATOR_COMMANDS.has(command) && !TENANT_COMMANDS.has(command)) {
      return reply.code(404).send({ error: 'Unsupported OpenPayd command', command })
    }
    if (!operator && !entitlements.active && command !== 'getStatus') {
      return reply.code(403).send({ error: 'Active OpenPayd entitlement required', command })
    }

    const proxied = await proxyConnector(command, {
      tenantId,
      environment: body.environment || 'sandbox',
      payload: body.payload || {},
      idempotencyKey: body.idempotencyKey,
      approvalRef: body.approvalRef
    })
    return reply.code(proxied.status).send(proxied.data)
  })
}
