#!/bin/bash

udbuild () {

local targets=(dev arm64 amd64 publish multi default)
local log_dir; local no_prompt; local packages
declare -A dimage; declare -A dinstall; declare -A dupdate

declare OPTION; declare OPTARG; declare OPTIND

BDIR=$(dirname "$(realpath "$BASH_SOURCE")")
export BDIR
# load script library
source $BDIR/lib/load.sh
BUILD_EFILE=""

# check for subcommands first
case "$1" in
  try)
  shift 1;  try_container "$@"; return $?  ;;
  load_env_file)
  echo -e "@@@@@@ loading build environment file for external use @@@@@@"
  BUILD_EFILE=$(echo -- "$@" | grep -oP -- '(?<=-e )[^ ]*')
  if source_env_file "$BUILD_EFILE"; then
  echo -e "@@@@@@@@@@@@@@@@@ returning to calling script @@@@@@@@@@@@@@@"
  else 
  return 1
  fi
  ;;
  build_src) shift 1; get_build_src "$@";  return $?  ;;
  help)
  ;&
  --help)
  ;&
  -help) shift 1; usage "$@"; return $? ;;
  source) type udbuild; return $? ;;
  image)
  shift 1
    case "$1" in
      name) shift 1; image_name "$@" ;;
      tag) shift 1; image_tag "$@" ;;
      push) shift 1; image_push "$@" ;;
      delete) shift 1; image_delete "$@" ;;
      exists) shift 1; image_exists "$@" ;;
      info) 
        shift 1
        case "$1" in
          arch) shift 1; image_arch "$@" ;;
          tags) shift 1; image_tags "$@" ;;
          id) shift 1; image_id "$@" ;;
          * ) image_info "$@"
        esac
      ;;  
      *) echo no image subcommand $1 ;;   
    esac
    return $?
  ;;
esac

[[ -z "$PS1" ]] || no_prompt=true
overwrite=true

while getopts 'ya:b:c:d:e:f:g:hi:lnopr:s:t:u:v:j:' OPTION; do
  # echo processing: option:$OPTION argument:$OPTARG index:$OPTIND remaining:${@:$OPTIND}
  case "$OPTION" in
  a)
    APPEND_BUILD_ENV=$OPTARG
  ;;
  b)
  # CUSTOM BASE IMAGE
    BASE_IMAGE=$OPTARG
    ;;
  y)
  # CUSTOM BASE IMAGE
    BASE_IMAGE_COPY=true
    ;;
  c)
    TRY_CMD=$OPTARG
      ;;
  d)
    # LINUX_DISTRO=$OPTARG
    LINUX_DISTRO=$OPTARG
    ;;
  e) 
   BUILD_EFILE=$OPTARG
   if ! source_env_file $BUILD_EFILE; then return 2; fi
   ;; 
  f)
    REBUILD=$OPTARG
  ;;
  g)
    TAG=$OPTARG
    ;;
  h)  
    usage
    return 0
  ;;
  i) 
   IMAGE_INFO=$OPTARG
   ;; 
 
  o)
    unset overwrite
  ;;
  v)
    VOLUME=$OPTARG
  ;;
  j)
    VERBOSE=$OPTARG
  ;;
  l)
  #  append distro name to image name
    APPEND_DISTRO=true
    ;;
  n) 
    nocache="--no-cache" 
  ;;    
  p)
    echo "build script will be run WITHOUT user prompts (i.e. non-interactive)"
    no_prompt=true
  ;;
  r)  
    REPO=$OPTARG
  ;;  
  s)
    # building source from which to bind into build, default is src/ in current directory
    BUILD_SRC=$OPTARG
    ;;    
  t)
    TARGET=$OPTARG
    ;;
  u)
    RUSER=$OPTARG
    ;;
  *)  
      echo "unknown $0 option -$OPTARG"
      usage
      return 1
  ;;
  esac
done

shift $((OPTIND - 1))

[[ ! $BUILD_EFILE ]] && source_env_file

if ! get_build_src; then 
 if [[ $no_prompt ]] ; then
    echo aborting the build...
    echo -e "\e[1;31mNOTE: use '_core_' to explicitly build with only the UCI core repo\e[1;37m"
    return 2
    else 
    echo "Do you want to build with only the UCI core" 
    read  -n 1 -p "instead? [y]=>" REPLY
    [[ $REPLY != "y" ]] && echo -e "\n" && return 2
    BUILD_SRC="_core_"
    echo -e "\n\e[1;31mNOTE: use '_core_' to explicitly build with only the UCI core\e[1;37m"
  fi
fi

TARGET=${TARGET:-default}
[[ ! "${targets[@]}" =~ $TARGET ]] && echo $TARGET is not a valid target && echo valid targets are: ${targets[@]} && exit 4

LINUX_DISTRO=${LINUX_DISTRO:-alpine}
if ! get_base_image; then return $?; fi

IMAGE_NAME=$(make_image_name $@) 

# TODO writing to existing tag untags existing image so write a new tag to that image then continue
# retag existing image and remove former tag
if [[ $(image_exists $IMAGE_NAME) ]]; then
  if [[ $overwrite ]]; then
    image_delete $IMAGE_NAME 
  else 
    newtag=$(date +'%d%H%M%S')
    echo image exists retaging $(image_name $IMAGE_NAME) with tag :$newtag  
    image_tag $IMAGE_NAME $IMAGE_NAME:$newtag
    image_tag -r $IMAGE_NAME
  fi 
fi  

ARCH=$(get_arch)
log_dir=$PWD/logs
mkdir -p $log_dir 
[[ $TARGET == "dev" ]] && VERBOSE=true

export BASE_IMAGE
export TAG
export IMAGE_NAME
export LINUX_DISTRO
export BUILD_SRC
export ARCH
export VERBOSE
export REBUILD

build_info

if [[ ! $no_prompt ]]; then
  read  -n 1 -p "do you want to continue [y]=>" REPLY
  [[ $REPLY != "y" ]] && echo -e "\n" && return 4
fi

# cat $BDIR/Dockerfile | grep -b5 -a5 ENTRY
# return

builder=default
if [[ $TARGET == "publish" ]]; then 
    builder=publish 
    pushd "$BDIR" > /dev/null || return 3
    if ! docker buildx ls | grep -q publish ; then
        echo publish builder does not exist, creating with docker-container driver 
        docker buildx create --name publish --driver docker-container >/dev/null
        docker buildx ls | grep publish
    fi
    popd > /dev/null || return 4
fi

# make a copy of build source locally in build directory
if [[ ! $BUILD_SRC = "_core_" ]]; then
  # copy  or bind build source directory to temporary .src/ subdirectory in build repo
  _env_dir=rootfs/opt/env
  [[ -d $BDIR/.src ]] && rm -rf $BDIR/.src
  [[ -d $BDIR/core/$_env_dir ]] && rm -rf $BDIR/core/$_env_dir
  if [[ $(which rsync 2> /dev/null ) ]]; then
  rsync -aAru ${BUILD_SRC:-src}/ $BDIR/.src
  rsync  -aAru $BDIR/.src/$_env_dir/ $BDIR/core/$_env_dir > /dev/null 2>&1
  else
  echo no rsync copying with cp
  /bin/cp -a ${BUILD_SRC:-src}/. $BDIR/.src > /dev/null 2>&1
  /bin/cp -a $BDIR/.src/rootfs/opt/env/. $BDIR/core/rootfs/opt/env > /dev/null 2>&1
  fi
fi  

echo run environment directory copied to core at $BDIR/core/$_env_dir
ls -la $BDIR/core/$_env_dir
 
# create Dockerfile from template
if ! source $BDIR/Dockerfile.d/create; then 
echo unable to create Dockerfile from template, aborting build
return 3
fi

if [[ -f $APPEND_BUILD_ENV ]]; then 
  if [[ ! $BUILD_SRC = "_core_" ]]; then
    echo "------ Including custom build environment at $APPEND_BUILD_ENV -------"
    cat $APPEND_BUILD_ENV
    echo -e "\n--------------------"
    echo | tee -a "$BDIR/.src/init/build.env" > /dev/null
    tee -a "$BDIR/.src/init/build.env" > /dev/null < "$APPEND_BUILD_ENV"
  fi  
    cat "$APPEND_BUILD_ENV" > "$BDIR/core/build.env"
# run in subshell to not affect $USER  
  /bin/bash <<"EOF" 
unset USER  
source "$BDIR/core/build.env"
[[ $USER_PW ]] && USER=${USER:-sysadmin}
if [[ $USER ]]; then
if [[ -f $PWD/$USER-permits ]]; then
echo sudo permits file: \'$USER-permits\' added to core build
/bin/cp -f $PWD/$USER-permits  $BDIR/core
fi 
fi
EOF
fi

pushd "$BDIR" > /dev/null || return 3

export BUILDING=true

echo -e "\n\e[1;31m######### RUNNING THE DOCKER BUILD COMMAND ######################"
echo running build command: docker buildx --builder ${builder} bake ${nocache} ${TARGET} 
echo -e "#################################################################\e[1;37m"
docker buildx --builder ${builder} bake ${nocache} ${TARGET}  2>&1 | tee "$log_dir/${IMAGE_NAME//\//-}build.log"
[[ $? == 0 ]] && echo succcess building image $IMAGE_NAME || exit_abnormal 5  
popd > /dev/null || return 4

# cleanup
echo cleaning up..
rm -rf $BDIR/.src $BDIR/core/build.env $BDIR/core/*-permits > /dev/null 2<&1
echo done cleaning
# try in container
if [[ ($TRY_CMD || $TARGET == "dev") ]]; then
 echo trying newly built image in a container
 echo name before try $IMAGE_NAME
 try_container build -m opt $([[ $TARGET == "publish" ]] && echo -p) ${TRY_CMD:-shell}
fi 

if [[ $TARGET == "private" ]]; then 
    echo pushing arm64 image $IMAGE_NAME to ${REPO:-docker hub}
    image_push -a -r $REPO $IMAGE_NAME
    echo pushing amd image $IMAGE_NAME to ${REPO:-docker hub}
    image_push -r $REPO $IMAGE_NAME
fi

}  

# if script was executed then call the function
(return 0 2>/dev/null) || udbuild "$@"