class Inspec::Resources::WindowsUser

def collect_user_details # rubocop:disable Metrics/MethodLength

rubocop:disable Metrics/MethodLength
https://msdn.microsoft.com/en-us/library/aa746340(v=vs.85).aspx
def collect_user_details # rubocop:disable Metrics/MethodLength
  return @users_cache if defined?(@users_cache)
  script = <<~EOH
    Function ConvertTo-SID { Param([byte[]]$BinarySID)
      (New-Object System.Security.Principal.SecurityIdentifier($BinarySID,0)).Value
    }
    Function Convert-UserFlag { Param  ($UserFlag)
      $List = @()
      Switch ($UserFlag) {
        ($UserFlag -BOR 0x0001) { $List += 'SCRIPT' }
        ($UserFlag -BOR 0x0002) { $List += 'ACCOUNTDISABLE' }
        ($UserFlag -BOR 0x0008) { $List += 'HOMEDIR_REQUIRED' }
        ($UserFlag -BOR 0x0010) { $List += 'LOCKOUT' }
        ($UserFlag -BOR 0x0020) { $List += 'PASSWD_NOTREQD' }
        ($UserFlag -BOR 0x0040) { $List += 'PASSWD_CANT_CHANGE' }
        ($UserFlag -BOR 0x0080) { $List += 'ENCRYPTED_TEXT_PWD_ALLOWED' }
        ($UserFlag -BOR 0x0100) { $List += 'TEMP_DUPLICATE_ACCOUNT' }
        ($UserFlag -BOR 0x0200) { $List += 'NORMAL_ACCOUNT' }
        ($UserFlag -BOR 0x0800) { $List += 'INTERDOMAIN_TRUST_ACCOUNT' }
        ($UserFlag -BOR 0x1000) { $List += 'WORKSTATION_TRUST_ACCOUNT' }
        ($UserFlag -BOR 0x2000) { $List += 'SERVER_TRUST_ACCOUNT' }
        ($UserFlag -BOR 0x10000) { $List += 'DONT_EXPIRE_PASSWORD' }
        ($UserFlag -BOR 0x20000) { $List += 'MNS_LOGON_ACCOUNT' }
        ($UserFlag -BOR 0x40000) { $List += 'SMARTCARD_REQUIRED' }
        ($UserFlag -BOR 0x80000) { $List += 'TRUSTED_FOR_DELEGATION' }
        ($UserFlag -BOR 0x100000) { $List += 'NOT_DELEGATED' }
        ($UserFlag -BOR 0x200000) { $List += 'USE_DES_KEY_ONLY' }
        ($UserFlag -BOR 0x400000) { $List += 'DONT_REQ_PREAUTH' }
        ($UserFlag -BOR 0x800000) { $List += 'PASSWORD_EXPIRED' }
        ($UserFlag -BOR 0x1000000) { $List += 'TRUSTED_TO_AUTH_FOR_DELEGATION' }
        ($UserFlag -BOR 0x04000000) { $List += 'PARTIAL_SECRETS_ACCOUNT' }
      }
      $List
    }
    $Computername = $Env:Computername
    $adsi = [ADSI]"WinNT://$Computername"
    $adsi.Children | where {$_.SchemaClassName -eq 'user'} | ForEach {
      New-Object PSObject -property @{
        uid = ConvertTo-SID -BinarySID $_.ObjectSID[0]
        username = $_.Name[0]
        description = $_.Description[0]
        disabled = $_.AccountDisabled[0]
        userflags = Convert-UserFlag  -UserFlag $_.UserFlags[0]
        passwordage = [math]::Round($_.PasswordAge[0]/86400)
        minpasswordlength = $_.MinPasswordLength[0]
        mindays = [math]::Round($_.MinPasswordAge[0]/86400)
        maxdays = [math]::Round($_.MaxPasswordAge[0]/86400)
        warndays = $null
        badpasswordattempts = $_.BadPasswordAttempts[0]
        maxbadpasswords = $_.MaxBadPasswordsAllowed[0]
        gid = $null
        group = $null
        groups = @($_.Groups() | Foreach-Object { $_.GetType().InvokeMember('Name', 'GetProperty', $null, $_, $null) })
        home = $_.HomeDirectory[0]
        shell = $null
        domain = $Computername
      }
    } | ConvertTo-Json
  EOH
  cmd = inspec.powershell(script)
  # cannot rely on exit code for now, successful command returns exit code 1
  # return nil if cmd.exit_status != 0, try to parse json
  begin
    users = JSON.parse(cmd.stdout)
  rescue JSON::ParserError => _e
    return nil
  end
  # ensure we have an array of groups
  users = [users] if !users.is_a?(Array)
  # convert keys to symbols
  @users_cache = users.map { |user| user.each_with_object({}) { |(k, v), h| h[k.to_sym] = v } }
end

def identity(username)

def identity(username)
  # TODO: we look for local users only at this point
  name, _domain = parse_windows_account(username)
  return if collect_user_details.nil?
  res = collect_user_details.select { |user| user[:username] == name }
  res[0] if !res.empty?
end

def list_users

def list_users
  collect_user_details.map { |user| user[:username] }
end

def parse_windows_account(username)

def parse_windows_account(username)
  account = username.split('\\')
  name = account.pop
  domain = account.pop if !account.empty?
  [name, domain]
end