import React from 'react'
import type { Address } from 'viem'
import { Box, Text } from 'ink'
import { Surface } from '../../../ui/Surface.js'
import { Select } from '../../../ui/Select.js'
import { theme } from '../../../ui/theme.js'
import type { ProfileUpdates, Step } from '../reducer.js'
import {
displayCustodyMode,
identityOwnerAddress,
readCustodyMode,
readIdentityStateString,
} from './state.js'
import { ensValidationReasonText, selectEnsStatus } from '../ens/state.js'
import { shortAddress } from '../shared/model/format.js'
import { FieldRow } from '../shared/components/FieldRow.js'
import { lastBackupLabel } from '../profile/identity.js'
import {
type AgentReconciliation,
} from '../shared/reconciliation/index.js'
const footerHint = (hint: string) => {hint}
type CustodyStep = Extract
interface CustodyEditFlowProps {
step: CustodyStep
reconciliation?: AgentReconciliation
vaultAddress?: Address
onSetStep: (step: Step) => void
onSwitchToAdvanced: (returnTo: Step, profileUpdates: ProfileUpdates) => void
onSwitchToSimple: (returnTo: Step, profileUpdates: ProfileUpdates) => void
onResumeAdvanced: (returnTo: Step) => void
onManageOperatorWallets: () => void
onPrepareTransfer: () => void
onBack: () => void
}
export function isCustodyEditStep(step: Step): step is CustodyStep {
return step.kind === 'custody-model'
|| step.kind === 'custody-advanced-confirm'
|| step.kind === 'custody-simple-confirm'
}
export const CustodyEditFlow: React.FC = ({
step,
reconciliation,
vaultAddress,
onSetStep,
onSwitchToAdvanced,
onSwitchToSimple,
onResumeAdvanced,
onManageOperatorWallets,
onPrepareTransfer,
onBack,
}) => {
const identity = step.identity
const registry = step.registry
const returnTo = step.returnTo
const state = (identity.state ?? {}) as Record
const custodyMode = readCustodyMode(state)
const ownerAddress = identityOwnerAddress(identity, reconciliation?.onChainOwner)
const activeOperator = readIdentityStateString(state, 'activeOperatorAddress')
const approvedOperatorCount = Array.isArray(state.approvedOperatorWallets)
? (state.approvedOperatorWallets as unknown[]).length
: 0
const agentName = readIdentityStateString(state, 'name')
const tokenLabel = identity.agentId ? `Token #${identity.agentId}` : 'Token #unknown'
const tokenOwner = identity.ownerAddress ?? identity.address
if (step.kind === 'custody-model') {
type Action = 'switch-advanced' | 'switch-simple' | 'resume-advanced' | 'cancel-advanced' | 'manage-operator-wallets' | 'back'
const onChainCustody = reconciliation?.custody
const midFlow = onChainCustody === 'mid-flow-uri-pending'
const isAdvanced = onChainCustody === 'advanced' || midFlow || custodyMode === 'advanced'
const vaultHolds = onChainCustody === 'advanced' || midFlow
const subtitle = midFlow
? 'Advanced setup pending.'
: isAdvanced
? 'Advanced custody active.'
: 'Simple custody active.'
const modeLabel = midFlow ? 'Advanced (setup pending)' : displayCustodyMode(isAdvanced ? 'advanced' : 'simple')
const options: Array<{ value: Action; role?: 'section' | 'utility'; label: string; hint?: string }> = []
if (midFlow) {
options.push({
value: 'resume-advanced',
label: 'Resume Advanced Setup',
})
options.push({
value: 'cancel-advanced',
label: 'Cancel Advanced Setup',
})
}
if (!isAdvanced) {
options.push({
value: 'switch-advanced',
label: 'Switch to Advanced',
hint: 'Operators publish',
})
} else {
if (!midFlow) {
options.push({
value: 'switch-simple',
label: 'Switch to Simple',
hint: 'Remove Vault',
})
}
options.push({
value: 'manage-operator-wallets',
label: 'Manage Operators',
hint: 'Add or revoke',
})
}
options.push({ value: 'back', label: 'Back', role: 'utility' })
const notice = step.kind === 'custody-model' ? step.notice : undefined
return (
{notice ? (
{notice}
) : null}
{(() => {
const ensStatus = selectEnsStatus(identity)
return (
{ensStatus.name}
: ensStatus.kind === 'issue'
? {ensStatus.name} ({ensValidationReasonText(ensStatus.reason)})
: Not Linked}
/>
)
})()}
{isAdvanced && vaultAddress ?
: null}
{isAdvanced ? (
1
? `${approvedOperatorCount} authorized`
: activeOperator
? shortAddress(activeOperator)
: 'None Authorized'}
muted={!activeOperator && approvedOperatorCount === 0}
/>
) : null}
{(() => {
const lastBackup = lastBackupLabel(identity)
return
})()}
)
}
if (step.kind === 'custody-advanced-confirm') {
type Action = 'confirm' | 'transfer' | 'back'
return (
{agentName ?
: null}
)
}
type Action = 'confirm' | 'back'
return (
{agentName ?
: null}
Operators lose access immediately.
)
}
const Row: React.FC<{ label: string; value: string; muted?: boolean }> = ({ label, value, muted }) => (
)