import { resolveAssistantAction } from '../assistant-action-resolver.mjs'

const HUB_ACTIONS = new Set([
  'hub.user.read_admin_summary',
  'hub.invite.list_pending',
  'hub.access_request.list_pending',
  'hub.user.block',
  'hub.user.unblock',
  'hub.membership.change_role',
  'hub.membership.disable',
  'hub.assistant_access.change_role',
])

const MEMBERSHIP_ROLES = new Set(['client_owner', 'client_admin', 'member'])
const CORE_ASSISTANT_ROLES = new Set(['blocked', 'member', 'admin'])

function requireValue(input, key) {
  const value = input[key]
  if (value === undefined || value === null || String(value).trim() === '') {
    throw new Error(`Missing required adapter input: ${key}`)
  }
  return String(value)
}

function encode(value) {
  return encodeURIComponent(String(value))
}

function makeIdempotencyKey(actionId, input) {
  if (input.idempotencyKey) return String(input.idempotencyKey)
  return [
    actionId,
    input.actorUserId || 'actor_unknown',
    input.targetUserId || input.membershipId || 'target_unknown',
    input.targetRole || input.targetAssistantRole || input.targetStatus || 'default',
  ].join(':')
}

function patchPlan(actionId, input, path, body, summary) {
  return {
    method: 'PATCH',
    path,
    body,
    headers: {
      'Content-Type': 'application/json',
      'Idempotency-Key': makeIdempotencyKey(actionId, input),
    },
    summary,
  }
}

function buildPlanForAction(actionId, input) {
  switch (actionId) {
    case 'hub.user.read_admin_summary':
      return {
        method: 'GET',
        path: '/api/admin/control-plane',
        query: {
          projection: 'users,memberships,services,grants,exceptions,invites,accessRequests',
          clientId: input.clientId || null,
        },
        summary: 'Read admin-visible Launcher control-plane summary and filter in adapter output.',
      }
    case 'hub.invite.list_pending':
      return {
        method: 'GET',
        path: '/api/admin/control-plane',
        query: {
          projection: 'invites',
          status: 'pending',
          clientId: input.clientId || null,
        },
        summary: 'Read Launcher invites and return pending invites visible in current admin scope.',
      }
    case 'hub.access_request.list_pending':
      return {
        method: 'GET',
        path: '/api/admin/control-plane',
        query: {
          projection: 'accessRequests,engineWorkflowAccessRequests,users,clients',
          status: 'pending',
          clientId: input.clientId || null,
        },
        summary: 'Read Launcher access requests and return pending requests visible in current admin scope.',
      }
    case 'hub.user.block':
      return patchPlan(
        actionId,
        input,
        `/api/admin/users/${encode(requireValue(input, 'targetUserId'))}/profile`,
        { globalStatus: 'blocked' },
        'Block Launcher user via guarded profile update route.',
      )
    case 'hub.user.unblock':
      return patchPlan(
        actionId,
        input,
        `/api/admin/users/${encode(requireValue(input, 'targetUserId'))}/profile`,
        { globalStatus: 'active' },
        'Unblock Launcher user via guarded profile update route.',
      )
    case 'hub.membership.change_role': {
      const targetRole = requireValue(input, 'targetRole')
      if (!MEMBERSHIP_ROLES.has(targetRole)) {
        throw new Error(`Invalid targetRole: ${targetRole}`)
      }
      return patchPlan(
        actionId,
        input,
        `/api/admin/memberships/${encode(requireValue(input, 'membershipId'))}`,
        { role: targetRole },
        'Change Launcher client membership role via guarded membership update route.',
      )
    }
    case 'hub.membership.disable':
      return patchPlan(
        actionId,
        input,
        `/api/admin/memberships/${encode(requireValue(input, 'membershipId'))}`,
        { status: 'disabled' },
        'Disable Launcher client membership via guarded membership update route.',
      )
    case 'hub.assistant_access.change_role': {
      const targetAssistantRole = requireValue(input, 'targetAssistantRole')
      if (!CORE_ASSISTANT_ROLES.has(targetAssistantRole)) {
        throw new Error(`Invalid targetAssistantRole: ${targetAssistantRole}`)
      }
      return patchPlan(
        actionId,
        input,
        `/api/admin/memberships/${encode(requireValue(input, 'membershipId'))}`,
        { coreAssistantRole: targetAssistantRole },
        'Change NDC Core Assistant access role via guarded membership update route.',
      )
    }
    default:
      throw new Error(`Unsupported HUB action: ${actionId}`)
  }
}

export async function buildHubLauncherAdminPlan(input = {}, options = {}) {
  const decision = options.decision || await resolveAssistantAction(input, options)
  const actionId = decision.action?.id

  if (!actionId) {
    return {
      ok: false,
      decision: 'unsupported_hub_action',
      reason: 'Input did not resolve to a supported HUB Launcher admin action.',
      actionDecision: decision,
    }
  }

  if (
    decision.decision !== 'allowed' &&
    !(options.planPreview === true && decision.decision === 'needs_confirmation')
  ) {
    return {
      ok: false,
      decision: decision.decision,
      reason: decision.reason,
      actionDecision: decision,
    }
  }

  if (!HUB_ACTIONS.has(actionId)) {
    return {
      ok: false,
      decision: 'unsupported_hub_action',
      reason: 'Input did not resolve to a supported HUB Launcher admin action.',
      actionDecision: decision,
    }
  }

  const plan = buildPlanForAction(actionId, input)
  const adapterReady = decision.action.adapterStatus === 'implemented'

  return {
    ok: true,
    decision: 'planned',
    adapterId: 'adapter.hub.launcher_admin_api',
    adapterStatus: decision.action.adapterStatus,
    executionReady: adapterReady,
    dryRunOnly: !adapterReady,
    gatewayActor: {
      userId: input.actorUserId || null,
      email: input.actorEmail || null,
      subject: input.actorSubject || null,
    },
    safety: {
      noDeleteRouteMapped: true,
      requiresExternalExecutor: true,
      sourceGuardedRoutesOnly: true,
      confirmationAlreadyChecked: decision.execution.confirmed || options.planPreview === true,
    },
    request: plan,
    actionDecision: decision,
  }
}
