#!/usr/bin/env python3
import sys
import os
import subprocess

build = "go build -o ./bin/gostore ./cmd/gostore/main.go"
build_dev = "go build -o " +\
    "./bin_dev/gostore_dev ./cmd/gostore/main.go"


def help() -> None:
    """Выводит справку по использованию"""
    s = """

СПРАВКА

    ./make.py
    ./make.py --help
        Выводит справку по использованию

    ./make.py build
        Сборка проекта

    ./make.py dev.run
        Отладка проекта

    ./make.py mod
        Обновление модулей/вендринга

    ./make.py test.run
        Тестирование

    ./make.py lint
        Запуск линтеров
    """
    print(s)


class TBuild:
    """Класс для сборки проекта"""

    def __init__(self):
        pass

    def run(self) -> None:
        print("Сборка проекта")
        os.system("go fmt ./...")
        t = TTest()
        t.run()
        linter = TLint()
        linter.run()
        os.system(build)
        os.system("strip -s ./bin/notify_service")
        os.system("upx -f ./bin/notify_service")


class TDev:
    """Класс для отладки проекта"""

    def __init__(self):
        pass

    def run(self) -> None:
        print("Сборка отладки проекта")
        print('Установка перменных окружения')
        os.unsetenv("STAGE")
        os.environ['STAGE'] = "local"

        print('Зачистка путей')
        os.system('rm -frd ./bin_dev')
        os.system('mkdir -p ./bin_dev/web')
        os.system('cp -r ./web ./bin_dev')
        os.system("go fmt ./...")
        os.system(build_dev)

        os.chdir('./bin_dev')
        os.system('./fedor_dev')


class TMod:
    """Класс для обновления модулей"""

    def __init__(self):
        pass

    def run(self) -> None:
        print("Обновление модулей (режим совместимости с Go 1.22)")
        os.system("go get -u ./...")
        os.system("go mod tidy -compat=1.22.0")
        os.system("go mod vendor")
        os.system("go fmt ./...")


class TTest:
    """Класс для тестирования"""

    def __init__(self):
        pass

    def run(self) -> None:
        print("Тестирование...")
        lst_cmd = ['go', 'test', '-shuffle=on', '-vet=all',
                   '-race', '-timeout', '30s', '-coverprofile',
                   'cover.out', './...']
        _result = subprocess.run(
            lst_cmd, stdout=subprocess.PIPE)
        result = _result.stdout.decode('utf-8')
        lst_cmd = ['go', 'tool', 'cover', '-func=cover.out']
        _result_cover = subprocess.run(
            lst_cmd, stdout=subprocess.PIPE)
        result_cover = _result_cover.stdout.decode('utf-8')
        result += result_cover
        out = ''
        out += self.cover_packet(result)
        out += self.cover_func(result)
        out += self.control_fail(result)
        result = result.replace('\t', '  ')
        result = result.replace('  ', ' ')
        result = result.replace('  ', ' ')
        out = out.replace("\t", " ")
        out = out.replace("  ", " ")
        print(f'==========[ OUT ]==========\n{result}\n')
        total = self.cover_total(result_cover)
        if total < '85.0%':
            out += f'Слишком низкое прокрытие тестами({total})\n'
        print(f'==========[ ANALIZE ]==========\n{out}\n')
        if out != '':
            print('==========[ FINAL FAIL ]==========\n')
            print(f'Покрытие примерно: {total}')
            sys.exit(100)

        print('==========[ FINAL OK ]==========\n')
        print(f'Покрытие тестами: {total}')

    def cover_total(self, result_cover: str) -> str:
        """Проверяет, достаточный уровень покрытия тестами
        """
        lst_cover = result_cover.split('\n')
        cover_total = lst_cover[-2]
        lst_cover = cover_total.split('\t')
        total = lst_cover[-1]
        return total

    def control_fail(self, result: str) -> str:
        """Проверяет, что тест провален
        """
        lst_str = result.split('\n')
        out = ''
        for _str in lst_str:
            if 'FAIL' in _str:
                if _str == 'FAIL':
                    continue
                out += 'TTest.control_fail(): тест провален'
                out += '\n'+_str+'\n\n'
        return out

    def cover_func(self, result: str) -> str:
        """Проверяет, что функция покрыта тестами
        """
        lst_str = result.split('\n')
        out = ''
        for _str in lst_str:
            if ('%' in _str) and\
                (_str.find('cover') == -1) and\
                    (_str.find('\t%v') == -1):
                substr1 = _str.split('\t')[-1]
                _s = substr1[:-1]
                if len(_s) > 2 and float(_s) < 40.0:
                    out += 'TTest.cover_func(): функция плохо покрыта тестами'
                    out += '\n'+_str+'\n\n'
        return out

    def cover_packet(self, result: str) -> str:
        """Проверяет, что пакет покрыт тестами
        """
        lst_str = result.split('\n')
        out = ''
        for _str in lst_str:
            if '?' in _str:
                out += 'TTest.cover_packet(): пакет не покрыт тестами'
                out += '\n'+_str+'\n'
        return out


class TLint:
    """Класс для запуска динтеров"""

    def __init__(self):
        pass

    def run(self) -> None:
        print("Проверка кода")
        os.system("go fmt ./...")
        os.system("golangci-lint run ./...")
        os.system("gocyclo -over 12 ./cmd/")
        os.system("gocyclo -over 12 ./internal/")
        os.system("gocyclo -over 12 ./pkg/")
        os.system("gosec ./...")


if __name__ == '__main__':
    os.system("clear")
    args = sys.argv
    if len(args) < 2:
        help()
        sys.exit(1)
    cmd = args[1]
    if cmd == "help":
        help()
        sys.exit(2)
    elif cmd == "build":
        b = TBuild()
        b.run()
    elif cmd == "mod":
        m = TMod()
        m.run()
    elif cmd == "test.run":
        t = TTest()
        t.run()
    elif cmd == "lint":
        linter = TLint()
        linter.run()
    elif cmd == "dev.run":
        d = TDev()
        d.run()
    elif cmd == "":
        help()
        sys.exit(3)
    sys.exit(0)
