#!/usr/bin/env bash
cd src
if [ -f debian/changelog ] || [ ! -d .git ]; then
    tamarin_info "Not a Git repository or Debian changelog already exists !"
    exit
else
    tamarin_info "Creating changelog with commits information."
fi

# Get pkg tags as tie points in commit history
pkg_tags="$(git for-each-ref --format '%(refname)' refs/tags | tac)"

# Set starting commit
ceiling_commit=$(git describe --match "build/*" --abbrev=0 2>/dev/null)
if [ -z "$ceiling_commit" ]
then
  ceiling_commit="HEAD"
fi
first_commit=$(git rev-list --max-parents=0 HEAD)

# Get commits log as changelog

current_release_tag=$(git describe --match "release/*" --abbrev=0 2>/dev/null)

if [[ -z ${current_release_tag} ]]
then
  tamarin_warn "No release tag found, you repo should have a tag like 'release/*'"
  tamarin_info "Assuming tag release/0.0.0 on first commit of branch master"
  current_release="release/0.0.0"
  current_release_tag=${first_commit}
else
  current_release=$current_release_tag
fi

touch debian/changelog

project_name=$(tamarin_db get project_name)
distribution=$(tamarin_db get distribution UNRELEASED)
urgency=$(tamarin_db get urgency low)
package_level=$(tamarin_db get package_level dev)

function get_hash {
  # Return commit hash from various pointer
  pointer="$1"
  echo "$(git log -n1 --format=%H ${pointer})"
}

function get_short_hash {
  # Return commit short hash from various pointer
  pointer="$1"
  echo "$(git log -n1 --format=%h ${pointer})"
}

function get_previous_pkg_tag {
  # Return previous pkg/* tag or current tag if no previous pkg/* exists. 
  commit="$1"
  echo "$(git describe --abbrev=0 --match='pkg/*' $commit 2>/dev/null)"
}

function parse_tag {
  tag="$1"
  flavor="${tag%%/*}"
  extended_version="${tag##*/}"
  if [ "$flavor" = "pkg" ]
  then
    exploded_version="$(echo $extended_version | sed "s/\([a-z0-9.]\+\)-\([0-9]\+\)\(-[a-z]\++[0-9]\+\)\?\(-\([0-9]\+\)-\(g[a-z0-9]\+\)\)\?$/version:\1 revision:\2 modification:\3 distance:\5 anchor:\6/")"
  elif [ "$flavor" = "release" ]
  then
    exploded_version="$(echo $extended_version | sed "s/\([a-z0-9.]\+\)\(-\([0-9]\+\)-\(g[a-z0-9]\+\)\)\?$/version:\1 distance:\3 anchor:\4/")"
  fi
  echo $exploded_version
}

function get_distance_from_tag {
  description_tag="$1"
  tag=${description_tag%-*-*}
  anchor="$2"
  if [[ "$(get_hash $tag)" =~ "$(get_hash $anchor)" ]]
  then
    echo 0
  else
    distance="$(parse_tag $description_tag)"
    distance="${distance#*distance:}"
    distance="${distance%% *}"
    echo $distance
  fi
}

function get_upstream_version_from_tag {
  tag="$1"
  upstream="$(parse_tag $tag)"
  upstream="${upstream#*version:}"
  upstream="${upstream%% *}"
  echo "$upstream"
}

function get_package_version_from_tag {
  tag="$1"
  package="$(parse_tag $tag)"
  package="${package#*revision:}"
  package="${package%% *}"
  echo "$package"
}

function get_distribution_from_tag {
  # tag pkg like pkg/<level>/<distrib>/<version>
  # <distrib> may be composed
  tag="$1"
  distribution="${tag#pkg/*/}"
  distribution="${distribution%/*}"
  distribution="${distribution/\//-}"
  echo $distribution
}

function get_previous_release_tag {
  # Return previous pkg/* tag or current tag if no previous pkg/* exists. 
  commit="$1"
  echo "$(git describe --abbrev=0 --always --match='release/*' $commit)"
}

function on_pkg_tag {
  # Return 1 if current commit is tagged with pkg/* tag.
  commit="$1"
  nearest_old_pkg_tag="$(get_previous_pkg_tag $commit)"
  if [ -n "${nearest_old_pkg_tag}" ] && [ "$(get_hash ${commit})" = "$(get_hash ${nearest_old_pkg_tag})" ]
  then
    return 0
  else
    return 1
  fi
}

function next_step {
  # Return previous pkg/* tag or first commit if no pkg/* tag exists
  commit="$1"
  if [ "$(get_hash $commit)" = "$(get_hash $first_commit)" ]
  then
    echo $commit
  elif on_pkg_tag $commit
  then
    nearest_old_pkg_tag="$(get_previous_pkg_tag ${commit}^1)"
  else
    nearest_old_pkg_tag="$(get_previous_pkg_tag ${commit})"
  fi
  if [[ "$nearest_old_pkg_tag" =~ 'pkg/' ]]
  then
    echo $nearest_old_pkg_tag
  else
    echo $first_commit
  fi
}

function date_from_commit {
  # Return date suitable for changelog entry signature
  commit="$1"
  if [ "$(get_hash ${commit})" = "$(get_hash HEAD)" ]
  then
    package_date=$(date --rfc-2822)
  else
    maintainer_commit="$(get_previous_pkg_tag $commit)"
    package_date="$(git tag -l --format='%(creator)' ${maintainer_commit})"
    package_date="${package_date##*> }"
    package_date="$(date --rfc-2822 -d @${package_date% *})"
  fi
  echo "$package_date"
}

function packager_from_commit {
  # Return Name <mail> id format, suitable for changelog entry signature
  commit="$1"
  if on_pkg_tag "${commit}"
  then
    maintainer_commit="$(get_previous_pkg_tag $commit)"
    maintainer="$(git tag -l --format='%(creator)' ${maintainer_commit})"
    maintainer="${maintainer%>*}>"
  else
    maintainer="$(git log -n1 --format='%cn <%ce>')"
  fi
  maintainer=$(tamarin_db get maintainer "${maintainer}")
  echo "$maintainer"
}

function next_version {
  set -x
  commit="$1"
  # upstream version is given by most recent of release or pkg tag
  previous_pkg="$(git describe --long --match='pkg/*' $commit 2>/dev/null)"
  previous_release="$(git describe --long --match='release/*' $commit 2>/dev/null)"
  if [ -n "$previous_release" ] && [ -n "$previous_pkg" ]
  then
    distance_from_pkg=$(get_distance_from_tag "$previous_pkg" "$commit")
    distance_from_release=$(get_distance_from_tag "$previous_release" "$commit")
    if [ $distance_from_release -le $distance_from_pkg ]
    then
      distance=$distance_from_release
      version="$(get_upstream_version_from_tag $previous_release)-1"
    else
      distance=$distance_from_pkg
      version="$(get_upstream_version_from_tag $previous_pkg)-$(expr $(get_package_version_from_tag $previous_pkg) + 1)"
    fi
  elif [ -n "$previous_release" ]
  then
    distance_from_release=$(get_distance_from_tag "$previous_release" "$commit")
    distance=$distance_from_release
    version="$(get_upstream_version_from_tag $previous_release)-1"
  elif [ -n "$previous_pkg" ]
  then
    distance_from_pkg=$(get_distance_from_tag "$previous_pkg" "$commit")
    distance=$distance_from_pkg
    version="$(get_upstream_version_from_tag $previous_pkg)-$(expr $(get_package_version_from_tag $previous_pkg) + 1)"
  else
    distance=$(git rev-list --no-merges --count ${commit}..${first_commit})
    version="0.0.0-1"
  fi
  if [ "$package_level" = 'dev' ] || [ "$package_level" = 'staging' ]
  then
    version="${version}~${package_level}+${distance}"
  fi
  echo $version
  set +x
}

function gen_changelog_entry {
  ceiling_commit=$1
  floor_commit="$(next_step "${ceiling_commit}")"
  if [ "$(get_hash ${ceiling_commit})" = "$(get_hash ${floor_commit})" ]
  then
    return 1
  fi
  if on_pkg_tag $ceiling_commit
  then
    ceiling_commit="$(get_previous_pkg_tag $ceiling_commit)"
    version="$(get_upstream_version_from_tag $ceiling_commit)-$(get_package_version_from_tag $ceiling_commit)"
    distribution="$(get_distribution_from_tag $ceiling_commit)"
  else
    tamarin_info "current commit $ceiling_commit"
    version=$(next_version $ceiling_commit)
    distribution="UNRELEASED"
  fi
  #current_release="$(git describe --abbrev=0 --always --match='release/*' $ceiling_commit)"
  tamarin_info "Création de l’entrée de changelog entre ${ceiling_commit} et ${floor_commit}"

  maintainer="$(packager_from_commit ${ceiling_commit})"
  package_date="$(date_from_commit ${ceiling_commit})"
  version=${version/_/-}
  changelog_entry="${project_name} (${version}) ${distribution}; urgency=${urgency}"
  echo "$changelog_entry" >> debian/changelog
  echo >> debian/changelog
  for commit in $(git log --no-merges --format='%H' ${floor_commit}..${ceiling_commit})
  do
    subject="$(git log -n1 --format=%s ${commit})"
    echo "  * ${subject}" >> debian/changelog
    #ceiling_commit="$(git log -n1 --format='%H' ${commit}^1)"
  done
  echo >> debian/changelog
  changelog_sign=" -- ${maintainer}  ${package_date}"
  echo "$changelog_sign" >> debian/changelog
  echo >> debian/changelog
  ceiling_commit=${floor_commit}
}

function gen_changelog() {
  limit=10
  while gen_changelog_entry $ceiling_commit
  do
    limit=`expr $limit - 1`
    echo $changelog_entry
    if [ "$limit" -le 0 ]
    then
      break
    fi
  done
}

gen_changelog
cp debian/changelog /dist/changelog