#!/bin/bash

# Colors for terminal
if test -t 1; then
    # check if it supports colors
    ncolors=$(tput colors)
    if test -n "$ncolors" && test $ncolors -ge 8; then
        NC="$(tput sgr0)"       # no color
        RED="$(tput setaf 1)"   # red
        WHITE="$(tput setaf 7)" # white
    fi
fi

exception="(HTTP|OpenID|OAuth|TLS|API|ID)"

# the "nolint: check-logs" comment should be places on the last line that the linter matches
exclude_linter="(?!.*//nolint: check-logs)"

function lintLogContainingUpperCase {
    word_char="[\.-0-9a-z ]"
    capital_word="([a-z]*[A-Z][a-zA-Z]*)"

    grep --with-filename -n -P "Msg[f]?\(\"(($word_char|$exception)*)(?!$exception)($capital_word)($exclude_linter)" $1
}

# lintLogStartingWithUpperCase searched for log messages that start with an upper case letter
function lintLogStartingWithUpperCase {
    grep --with-filename -n "Msg[f]\?(\"[A-Z]" $1 | grep -v -P "Msg[f]?\(\"$exception($exclude_linter)"
}

# lintLogStartingWithComponent searches for log messages that starts with a component "component:"
function lintLogStartingWithComponent {
    # We'll check for different functions that can generate errors or logs. If they start with 
    # a number words followed by ":", it's considered as starting with a component.
    # Examples: '.Msgf("component:")', '.Errorf("com ponent:")', '.Msg("com-ponent:")'
    grep --with-filename -n -E "(Errorf|errors.New|Msg[f]?)\(\"[a-zA-Z-]+( [a-zA-Z-]+){0,1}:($exclude_linter)" $1
}

# lintErrorLogsBeggining searches for log messages that don't start with "failed to"
function lintErrorLogsBeggining {
    grep --with-filename -n -P "Error\(\)(?:.*)\n?.(?:.*)Msg[f]?\(\"(?!(failed to|failed due|invalid|unexpected|unsupported))($exclude_linter)" $1
}

function printLintError {
    errReason=$1
    errPathAndContent=$2

    IFS=':' read -r errPath errLine errLineContent <<< "$errPathAndContent"
    errLocation="$errPath:$errLine"

    if test -t 1; then
        echo -e "${WHITE}$errLocation${NC}: ${RED}$errReason${NC}\n\t$errLineContent"
    else
        echo "$errLocation: $errReason: $errLineContent"
    fi
}

files=$(find . -name '*.go' | grep -v '_test.go')

found_linting_error=false

for file in $files
do
    lintOutput=$(lintLogStartingWithUpperCase "$file")
    if [ $? -eq 0 ]; then
        found_linting_error=true
        while IFS= read -r line; do
            printLintError "Log message should not start with a CAPITAL letter" "$(echo $line | tr -s [:space:])"
        done <<< "$lintOutput"
    fi 

    lintOutput=$(lintLogStartingWithComponent "$file")
    if [ $? -eq 0 ]; then
        found_linting_error=true
        while IFS= read -r line; do
            printLintError "Log message should not start with the component (ex: 'component:', 'mixed component-with-dash:')" \
            "$(echo $line | tr -s [:space:])"
        done <<< "$lintOutput"
    fi

    lintOutput=$(lintErrorLogsBeggining "$file")
    if [ $? -eq 0 ]; then
        found_linting_error=true
        while IFS= read -r line; do
            printLintError "Error messages should start with 'failed to'" \
            "$(echo $line | tr -s [:space:])"
        done <<< "$lintOutput"
    fi
done

if [ $found_linting_error = true ]; then
    exit 1
fi

exit 0