Private/Registry.psm1

#!/usr/bin/env pwsh
using namespace System
using namespace System.Collections.Generic

using module ./Exceptions.psm1
# using module ./TwilioCli.psm1

# ─────────────────────────────────────────────────────────────────────────────
# API Registry – maps "api:topic:action" → a script-block that calls the SDK.
# Each entry also advertises which extra flags it accepts (its schema addendum).
#
# Key format : "<topic>:<action>" (e.g. "messages:list")
# Value : @{ Script=[ScriptBlock]; Flags=[Object[]] }
#
# The script-block receives two named parameters:
# $cmd – the TwilioApiCommand instance (has ParsedArgs & TwilioClient)
# $client – the resolved TwilioRestClient (can be $null for mockable paths)
# ─────────────────────────────────────────────────────────────────────────────
class TwilioApiRegistry {
  static hidden [hashtable] $_registry = $null

  static [hashtable] Get() {
    if ($null -ne [TwilioApiRegistry]::_registry) {
      return [TwilioApiRegistry]::_registry
    }

    [TwilioApiRegistry]::_registry = @{

      # ── Messages ────────────────────────────────────────────────────────────
      'messages:list'   = @{
        Description = 'List messages in your Twilio account'
        Flags       = [ParamBase]@('limit', [string], "50")
        Script      = {
          param($cmd, $client)
          $limit = if ($cmd.ParsedArgs.ContainsKey('limit')) { [int]$cmd.ParsedArgs['limit'].Value } else { 50 }
          $TypeAcceleratorsClass = [PsObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')
          $MsgResource = $TypeAcceleratorsClass::Get['MessageResource']
          $results = $MsgResource::Read($limit, $client)
          return $cmd.Output($results)
        }
      }

      'messages:create' = @{
        Description = 'Send a new Twilio message'
        Flags       = [ParamBase[]]@(
          ('to', [string], ''),
          ('from', [string], ''),
          ('body', [string], '')
        )
        Script      = {
          param($cmd, $client)
          $to = $cmd.ParsedArgs['to'].Value
          $from = $cmd.ParsedArgs['from'].Value
          $body = $cmd.ParsedArgs['body'].Value
          if ([string]::IsNullOrWhiteSpace($to) -or [string]::IsNullOrWhiteSpace($body)) {
            Write-Host 'Error: --to and --body are required.' -ForegroundColor Red; return $null
          }
          $TypeAcceleratorsClass = [PsObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')
          $MsgResource = $TypeAcceleratorsClass::Get['MessageResource']
          $PhoneNumber = $TypeAcceleratorsClass::Get['PhoneNumber']
          $Promoter = $TypeAcceleratorsClass::Get['Promoter']
          $toNum = $Promoter::Promote($to, $PhoneNumber)
          $fromNum = $Promoter::Promote($from, $PhoneNumber)
          $result = $MsgResource::Create($toNum, $fromNum, $body, $client)
          return $cmd.Output($result)
        }
      }

      'messages:fetch'  = @{
        Description = 'Fetch a single message by SID'
        Flags       = [ParamBase]@('sid', [string], '')
        Script      = {
          param($cmd, $client)
          $sid = $cmd.ParsedArgs['sid'].Value
          if ([string]::IsNullOrWhiteSpace($sid)) {
            Write-Host 'Error: --sid is required.' -ForegroundColor Red; return $null
          }
          $TypeAcceleratorsClass = [PsObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')
          $MsgResource = $TypeAcceleratorsClass::Get['MessageResource']
          $FetchOpts = $TypeAcceleratorsClass::Get['FetchMessageOptions']
          $opts = [Activator]::CreateInstance($FetchOpts, @($sid))
          $result = $MsgResource::Fetch($opts, $client)
          return $cmd.Output($result)
        }
      }

      # ── Accounts ─────────────────────────────────────────────────────────────
      'accounts:fetch'  = @{
        Description = 'Fetch account details'
        Flags       = [ParamBase]@('sid', [string], '')
        Script      = {
          param($cmd, $client)
          $sid = $cmd.ParsedArgs['sid'].Value
          if ([string]::IsNullOrWhiteSpace($sid) -and $null -ne $client) {
            $sid = $client.AccountSid
          }
          $TypeAcceleratorsClass = [PsObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')
          $AccResource = $TypeAcceleratorsClass::Get['AccountResource']
          $result = $AccResource::Fetch($null, $sid)
          return $cmd.Output($result)
        }
      }

      # ── Verify ───────────────────────────────────────────────────────────────
      'verify:start'    = @{
        Description = 'Start a verification'
        Flags       = [ParamBase[]]@(
          ('to', [string], ''),
          ('channel', [string], 'sms'),
          ('service-sid', [string], '')
        )
        Script      = {
          param($cmd, $client)
          $to = $cmd.ParsedArgs['to'].Value
          $channel = $cmd.ParsedArgs['channel'].Value
          $serviceSid = $cmd.ParsedArgs['service-sid'].Value
          if ([string]::IsNullOrWhiteSpace($to) -or [string]::IsNullOrWhiteSpace($serviceSid)) {
            Write-Host 'Error: --to and --service-sid are required.' -ForegroundColor Red; return $null
          }
          $TypeAcceleratorsClass = [PsObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')
          $VRes = $TypeAcceleratorsClass::Get['VerificationResource']
          $result = $VRes::Create($serviceSid, $to, $channel, $client)
          return $cmd.Output($result)
        }
      }

      'verify:check'    = @{
        Description = 'Check a verification code'
        Flags       = [ParamBase[]]@(
          ('to', [string], ''),
          ('code', [string], ''),
          ('service-sid', [string], '')
        )
        Script      = {
          param($cmd, $client)
          $to = $cmd.ParsedArgs['to'].Value
          $code = $cmd.ParsedArgs['code'].Value
          $serviceSid = $cmd.ParsedArgs['service-sid'].Value
          if ([string]::IsNullOrWhiteSpace($to) -or [string]::IsNullOrWhiteSpace($code) -or [string]::IsNullOrWhiteSpace($serviceSid)) {
            Write-Host 'Error: --to, --code and --service-sid are required.' -ForegroundColor Red; return $null
          }
          $TypeAcceleratorsClass = [PsObject].Assembly.GetType('System.Management.Automation.TypeAccelerators')
          $VRes = $TypeAcceleratorsClass::Get['VerificationResource']
          $result = $VRes::Check($serviceSid, $to, [int]$code, $client)
          return $cmd.Output($result)
        }
      }
    }

    return [TwilioApiRegistry]::_registry
  }

  static [string[]] GetTopics() {
    return [TwilioApiRegistry]::Get().Keys | Sort-Object
  }

  static [hashtable] Lookup([string]$topicAction) {
    $reg = [TwilioApiRegistry]::Get()
    if ($reg.ContainsKey($topicAction)) { return $reg[$topicAction] }
    return $null
  }
}