#!/usr/bin/env bash
#clear
#export PS4='\e[90m+${LINENO} in ${#BASH_SOURCE[@]}>${FUNCNAME[0]}:${BASH_SOURCE[@]##*/} \e[0m'
#set -x

#echo "starting: $0 <LOG_LEVEL=$1>"

user.id.completion() {
  echo "-u -n" 
  echo "-g"
}

user.id() # <options="-u -n"> # shows the user id. Without parameters it shows the also all groups
{
  id "$@"
}

user.ssh.status.completion() {
  echo log
}

user.ssh.status() # <?log> # returns 1 if ther is no ssh init. use log as argument if you want to see the output
{
  ossh.isInstalled "$@"
}

user.in() { # <sshId> # choose an other identity from user list.other.identities
  local sshId="$1"
  if [ -n "$1" ]; then
    shift
  fi

  if [ -z "$CURRENT_SSH_DIR" ]; then
    export CURRENT_SSH_DIR="$HOME/.ssh"
    config set CURRENT_SSH_DIR $CURRENT_SSH_DIR
  fi

  case $sshId in
    '')
      important.log "current sshId is: $CURRENT_SSH_DIR"
    ;;
    main)
      CURRENT_SSH_DIR="$HOME/.ssh"
      config set CURRENT_SSH_DIR $CURRENT_SSH_DIR
      success.log "new sshId is main: $CURRENT_SSH_DIR"
    ;;
    /*|~/*)
      CURRENT_SSH_DIR="$sshId"
      config set CURRENT_SSH_DIR $CURRENT_SSH_DIR
      success.log "new sshId is: $CURRENT_SSH_DIR"
    ;;
    *)
      CURRENT_SSH_DIR="$HOME/.ssh/ids/$sshId"
      config set CURRENT_SSH_DIR $CURRENT_SSH_DIR
      success.log "new sshId is: $CURRENT_SSH_DIR"

    ;;
  esac

  RESULT="$CURRENT_SSH_DIR"
  RETURN="$1"
}

user.parameter.completion.sshId() {
  user.list.other.identities
  echo "main"
}

private.get.sshDir() {
  local sshDir="$1"
  if [ -z "$1" ]; then
    sshDir="$CURRENT_SSH_DIR"
  fi
  if [ -z "$sshDir" ]; then
    sshDir="$HOME/.ssh"
  fi
  shift

  create.result 0 "$sshDir" "$1"
  info.log "$RESULT"
  return $(result)
}

user.ssh.get.key.name() { # # creates a good key name fot this user and host
  ossh.get.key.name
}

user.ssh.set.key.name() {
  ossh.set.key.name "$@"
}

user.ssh.get.file.name() { # # gets the actual key file name (instead of the best key name from get.key.name )
  ossh.get.file.name "$@"
}

user.ssh.rootkey.push() {
  local sshConfigName="$1"
  # if [ -z "$1" ]; then
  #   sshConfigName="$CURRENT_SSH_DIR"
  # fi
  # if [ -z "$sshDir" ]; then
  #   sshDir="$HOME/.ssh"
  # fi
  shift

  private.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  user.ssh.get.file.name $sshDir
  if [ -n "$1" ]; then
    shift
  fi
  local sshKeyName="$RESULT"

  scp $sshDir/public_keys/$sshKeyName.public_key $sshConfigName:/root/.ssh/public_keys
  ssh $sshConfigName ". /root/config/user.env; user update.authorized_keys"
}

user.ssh.rootkey.file.push() {
  local sshConfigName="$1"
  # if [ -z "$1" ]; then
  #   sshConfigName="$CURRENT_SSH_DIR"
  # fi
  # if [ -z "$sshDir" ]; then
  #   sshDir="$HOME/.ssh"
  # fi
  shift

  local sshPublicKeyFile="$1"
  if [ -n "$sshPublicKeyFile" ]; then
    shift
    scp $sshPublicKeyFile $sshConfigName:/root/.ssh/public_keys
    ssh $sshConfigName ". /root/config/user.env; user update.authorized_keys"
  else
    error.log "no public key file provided as second parameter"
  fi


}

user.ssh.rootkey.file.revoke() {
  local sshConfigName="$1"
  # if [ -z "$1" ]; then
  #   sshConfigName="$CURRENT_SSH_DIR"
  # fi
  # if [ -z "$sshDir" ]; then
  #   sshDir="$HOME/.ssh"
  # fi
  shift

  local sshPublicKeyFile="$1"
  if [ -n "$sshPublicKeyFile" ]; then
    shift
    ssh $sshConfigName ". /root/config/user.env; mv  /root/.ssh/public_keys/$(basename $sshPublicKeyFile)  /root/.ssh/deactive.public_keys/$(basename $sshPublicKeyFile);    user update.authorized_keys"
  else
    error.log "no public key file provided as second parameter"
  fi


}


user.ssh.rootkey.pull() {
    local sshConfigName="$1"
  # if [ -z "$1" ]; then
  #   sshConfigName="$CURRENT_SSH_DIR"
  # fi
  # if [ -z "$sshDir" ]; then
  #   sshDir="$HOME/.ssh"
  # fi
  shift



  scp $sshConfigName:/root/.ssh/id_rsa.pub ./root.$sshConfigName.public_key
  #ssh $sshConfigName ". /root/config/user.env; user update.authorized_keys"
}

user.ssh.rootkey.push.completion() {
  grep '^Host' ~/.ssh/config ~/.ssh/config.d/* 2>/dev/null | cut -d ' ' -f 2-
}

user.ssh.rename.files() { # <sshKeyName> # renames the keys to the new base name <sshKeyName>
  user.ssh.get.file.name
  local sshKeyFileName="$RESULT"

  local sshKeyName="$1"
  if [ -z "$sshKeyName" ]; then
    user.ssh.get.key.name
    sshKeyName="$RESULT"
  fi
  shift

  private.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  #ls -al $sshDir/public_keys/${sshKeyFileName}*
  #ls -al $sshDir/private_key/${sshKeyFileName}*

  mv $sshDir/private_key/${sshKeyFileName}.private_key $sshDir/private_key/${sshKeyName}.private_key
  mv $sshDir/public_keys/${sshKeyFileName}.public_key $sshDir/public_keys/${sshKeyName}.public_key 

  tree $sshDir

}

user.init() # # creates a new SSH key pair for this user
{
  if user.ssh.status log; then
    console.log ".ssh exists"
    tree ~/.ssh
  else
    console.log "initialising new .ssh"
    ssh-keygen
    mkdir ~/.ssh/public_keys
    mkdir ~/.ssh/private_key
    user.ssh.get.key.name
    local sshKeyName="$RESULT"
    cp ~/.ssh/id_rsa ~/.ssh/private_key/$sshKeyName.private_key
    cp ~/.ssh/id_rsa.pub ~/.ssh/public_keys/$sshKeyName.public_key
    {
      echo "
Host WODA.test
 User root
 Port 22
 HostName 178.254.18.182
 IdentityFile ~/.ssh/id_rsa

Host WODA.dev.root
 User root
 Port 22
 HostName cerulean.it
 IdentityFile ~/.ssh/id_rsa
 
Host WODA.dev
 User developking
 Port 22
 HostName cerulean.it
 IdentityFile ~/.ssh/id_rsa
      "

    } >~/.ssh/config
  oo cmd tree >/dev/null
  tree ~/.ssh
  fi
}

user.ssh.create.folders() {
  private.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"
  
  mkdir  $sshDir/public_keys                                      
  mkdir $sshDir/private_key
  user.ssh.get.key.name                                   
  local sshKeyName="$RESULT"
  cp $sshDir/id_rsa $sshDir/private_key/$sshKeyName.private_key
  cp $sshDir/id_rsa.pub $sshDir/public_keys/$sshKeyName.public_key
}


user.update.authorized_keys() # # updated all keys in .ssh/public_keys as authorized
{

  private.get.sshDir "$1"

  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  if user.ssh.status; then
    info.log "updating $sshDir/authorized_keys"
    rm $sshDir/authorized_keys
    cat $sshDir/public_keys/* >>~/.ssh/authorized_keys

    chmod 700 $sshDir
    chmod 600 $sshDir/authorized_keys
    chmod 600 $sshDir/id_rsa
  fi
}

user.get() # <property> <username> # 
{
  local property="$1"
  if [ -n "$1" ]; then shift; fi

  local username="$1"
  if [ -n "$1" ]; then shift; fi

  if os.check private.get.$property "$username"; then
    $RESULT "$username"
  else
    important.log "$RESULT is not supported"
  fi  
  RETURN="$1"
}

user.parameter.completion.property() {
  echo "home"
  echo "basehome"
  echo "shell"
  echo "info"
  echo "name"
}

user.parameter.completion.username() {
  user.list "$@"
}

private.get.info.linux() # <username> # 
{
  getent passwd "$1"
  # mac osx
  #dscl . -read /Users/marcel
}

private.get.name.linux() #  # 
{
  id -u -n
}

private.get.name.darwin() #  # 
{
  private.get.name.linux  
}

private.get.basehome.linux() # <username> # 
{
  private.get.basehome.darwin "$@"
}

private.get.basehome.darwin() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  if [ "$username" = "root" ]; then
      username="developking"
  fi 
  
  this.absolutePath "$(user.get home $username)/.."
  echo $RESULT
}

private.get.home.linux() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  source line 
  private.get.info.linux "$username" \
  | line.split ":" \
  | line.trim.quoted \
  | line.unquote \
  | line select 6
  
  #dscl . -read /Users/marcel | line find Home | line split ":" | line unquote | line select 2
}

private.get.shell.linux() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then shift; fi

  source line 
  private.get.info.linux "$username" \
  | line.split ":" \
  | line.unquote \
  | line select 7
  
  #dscl . -read /Users/marcel | line find Shell | line split ":" | line unquote | line select 2

}

private.get.shell.darwin() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  source line 
  dscl . -read /Users/"$username"  \
  | line.find Shell \
  | line.split ":" \
  | line.trim.quoted \
  | line.unquote \
  | line.select 2
}

private.get.home.darwin() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  source line 
  dscl . -read /Users/"$username"  \
  | line.find Home \
  | line.split ":" \
  | line.trim.quoted \
  | line.unquote \
  | line.select 2
}

private.get.info.darwin() # <username> # 
{
  local username="$1"
  if [ -n "$1" ]; then 
    shift; 
  else
    username=$USER
  fi

  source line 
  dscl . -read /Users/"$username"  
}

user.create()  # <username> <?uid> <?gid> # creates a new user with home dir
{

  local name=$1
  local custom_uid=
  local custom_gid=
  shift
  if [ -n "$1" ]; then
    custom_uid=$1
    shift
  fi
  if [ -n "$1" ]; then
    custom_gid=$1
    shift
  fi

  # if [ -d $REPO_DIR ]; then
  #   warn.log "Repository does not exist: $REPO_DIR"
  # fi

  if [ -n "$custom_uid" ]; then
    $SUDO useradd -m $name -u$custom_uid -g$custom_gid -s /bin/bash
  else
    $SUDO useradd -m $name -s /bin/bash
  fi
  $SUDO usermod -aG sudo $name
  useradd -g dev $name 
  #once.user.init $name
  

  RETURN=$1

}

user.delete.linux() { # <username> # removes the user and all its files
  local username="$1"
  if [ -n "$1" ]; then shift; fi
  userdel -rf $username
}

# duplicat
# user.check.group() {
#   local group=$1
#   shift 
#   if [ $(getent group admin) ]; then
#     create.result 0 "group $group exists" "$1"
#   else
#     create.result 1 "group $group does not exist"  "$1"
#   fi
#   echo "$RESULT"
#   return "$(result)"
# }

user.list() {
  user.list.all "$1" | line filter "^_"
}

user.list.all() {
  compgen -u "$1"
}

user.list.other.identities() {
  ls $HOME/.ssh/ids
}

user.get.current.identity() {
  private.get.sshDir
  #echo "$RESULT"
}

user.list.groups() {
  compgen -g "$1"
}

user.login() # <userName> # 
{
  env -i su $1
} 

user.group.add() # <groupName> <?toUsername> # adds <toUsername> to group <groupName> if both exist
{

  local groupName="$1"
  if [ -n "$1" ]; then
    groupName="$1"
    shift
  else
    error.log "no ${YELLOW}groupName${RED} was specified"
    return 1
  fi 

  local toUsername="$1"
  if [ -n "$1" ]; then
    toUsername="$1"
    shift
  else
    console.log "no ${YELLOW}toUsername${NORMAL} was specified"
  fi 

  if user.check.group "$groupName"; then
    info.log "groupName already exists: $groupName"
  else
    console.log "creating groupName: $OS_CMD_GROUP_ADD $groupName"
    $SUDO $OS_CMD_GROUP_ADD $groupName
  fi

  if [ -n "$toUsername" ]; then
    $SUDO $OS_CMD_USER_MOD "$groupName" "$toUsername"
  fi
}

user.group.check() # <groupName> # checks if a group exists
{
  user.check.group "$@"
}

user.check.group() # <groupName> # checks if a group exists
{
  source line
  local result=$( compgen -g "$1" | line.format "%s:" | line.find "$1:" | line.count )
  if this.isNumber "$result"; then
    if [ $result -eq 1 ];then 
      success.log "group exists: $1"
      return 0
    else
      if [ $result -eq 0 ];then
            warn.log  "group does ${RED}NOT${YELLOW} exist: ${RED}$1${NORMAL}"
            compgen -g "$1"
            return 1
      fi 
      warn.log "multiple groups exist: $1"
      compgen -g "$1"
      return 0
    fi
  else
    warn.log "reult: $result"
    return 1
  fi
}

user.ssh.backup() {
  local name="$1"
  if [ -z "$name" ]; then
    name="bak"
  fi
  if [ -n "$1" ]; then
    shift
  fi

  private.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  cp -R $sshDir ssh.$name 
}

user.ssh.restore() {
  local name="$1"
  if [ -z "$name" ]; then
    name="bak"
  fi
  if [ -n "$1" ]; then
    shift
  fi

  private.get.sshDir "$1"
  if [ -n "$1" ]; then
    shift
  fi
  local sshDir="$RESULT"

  rm -Rf $sshDir 
  cp -R ssh.$name $sshDir 
}

user.usage()
{
  local this=${0##*/}
  echo "You started 
$0
  
  Usage:
  $this: command   description and Parameter

      usage                   prints this dialog while it will print the status when there are no parameters          
      v                       print version information

      in 
  
      list  
      create                  expects \"name <uid gid>\" and creates a new user with home dir
      update.authorized_keys  <?sshDir:\"~/.ssh\">
  
      ssh.status log          logs if ther is an ssh config
      ssh.init                creates a new ssh config
  
      ssh.rename.files        <newName> <?sshDir:\"~/.ssh\">
      ssh.get.key.name      
      ssh.get.file.name       <?sshDir:\"~/.ssh\">

      ssh.backup              <newName> <?sshDir:\"~/.ssh\"> will result in a ssh.newName folder
      ssh.restore             <newName> <?sshDir:\"~/.ssh\"> CAREFULL!!! ssh.newName in sshDir and if not present overwites the current .ssh folder

      ssh.rootkey.file.revoke <sshConfigName> <publicKeyFile>      revokes access for the public key file
      ssh.rootkey.file.push   <sshConfigName> <publicKeyFile>      pushes the public key file        to the root of the specified ssh server and makes it authorized
      ssh.rootkey.push        <sshConfigName> <?sshDir:\"~/.ssh\"> pushes the public key from sshDir to the root of the specified ssh server and makes it authorized
      ssh.rootkey.pull        <sshConfigName> gets the root public key of the specified ssh server
      ----      --------------------------"
  this.help
  echo "
  ${NO_COLOR}
  Examples
    user init
    
    user in ./KPP/ssh.developer ssh.get.file.name
    user ssh.get.file.name ./KPP/ssh.developer

  OS details:
      OS_CMD_USER_ADD=$OS_CMD_USER_ADD
      OS_CMD_USER_MDO=$OS_CMD_USER_MOD  
      OS_CMD_USER_DEL=$OS_CMD_USER_DEL
      OS_CMD_GROUP_ADD=$OS_CMD_GROUP_ADD
  "
}

private.user.init() {
  if [ -z "$USER" ]; then
    USER=$(id -u -n)
  fi
  ONCE_SUDO=sudo

  if [ -f $CONFIG_PATH/os.commands.env ]; then
    source $CONFIG_PATH/os.commands.env
  else
    if [ -x "$(command -v adduser)" ]; then
      export OS_CMD_USER_ADD="adduser"
    fi
    if [ -x "$(command -v useradd)" ]; then
      export OS_CMD_USER_ADD="useradd"
    fi
    if [ -x "$(command -v userdel)" ]; then
      export OS_CMD_USER_DEL="userdel"
    fi
    if [ -x "$(command -v usermod)" ]; then
      export OS_CMD_USER_MOD="usermod -a -G"
    fi

    if [ -x "$(command -v addgroup)" ]; then
      export OS_CMD_GROUP_ADD="addgroup"
    fi
    if [ -x "$(command -v groupadd)" ]; then
      export OS_CMD_GROUP_ADD="groupadd"
    fi
    oo pm.discover
  fi
}

user.start()
{
  #echo "sourcing init"
  source this
  source ossh
  source os
  private.user.init

  # if [ -z "$1" ]; then
  #   status.discover "$@"
  #   return 0
  # fi

  this.start "$@"
}

user.start "$@"

