import os
import argparse
import shutil

GIT_HASH = "e3e4e86fdf3bb66747436c485453fd07"
GIT_HASH_BIN = bytes.fromhex(GIT_HASH)
INITIAL_DIR = os.path.dirname(os.path.abspath(__file__))

APP_VER_ADDRESS = 0x6D000
GOLDEN_APP_VER_ADDRESS = 0xDE000
GOLDEN_ADDRESS = 0x0071000
GOLDEN_APP_VERSION_SHIFTED = GOLDEN_APP_VER_ADDRESS-GOLDEN_ADDRESS


def get_git_hash():
    # Проверяем текущую директорию. Если не initial_dir, то переходим в нее
    print(f"Текущая директория: {os.getcwd()}")
    print(f"Исходная директория: {INITIAL_DIR}")
    if os.getcwd() != INITIAL_DIR:
        os.chdir(INITIAL_DIR)
    # Переходим в директорию с git репозиторием
    git_dir = find_git_repository()
    if git_dir is None:
        print("Не удалось найти git репозиторий.")
        return None
    os.chdir(git_dir)
    # Получаем git hash --short
    try:
        git_hash = os.popen('git rev-parse --short HEAD').read().strip()
    except Exception as e:
        print(f"Ошибка при получении git hash: {e}")
        git_hash = None
    # Возвращаемся в исходную директорию
    os.chdir(os.path.dirname(INITIAL_DIR))
    return git_hash

def get_git_tag():
      # Проверяем текущую директорию. Если не initial_dir, то переходим в нее
    if os.getcwd() != INITIAL_DIR:
        os.chdir(INITIAL_DIR)
    # Переходим в директорию с git репозиторием
    git_dir = find_git_repository()
    if git_dir is None:
        print("Не удалось найти git репозиторий.")
        return None
    os.chdir(git_dir)
    # Получаем git tag
    try:
        git_tag = os.popen('git describe --tags').read().strip()
    except Exception as e:
        print(f"Ошибка при получении git tag: {e}")
        git_tag = None
    # Возвращаемся в исходную директорию
    os.chdir(os.path.dirname(INITIAL_DIR))
    return git_tag

def find_git_repository():
    current_dir = INITIAL_DIR
    
    try:
        # Выходим выше по дереву каталогов, пока не найдем .git
        while True:
            if os.path.isdir(os.path.join(current_dir, '.git')):
                git_dir = os.path.abspath(os.path.join(current_dir, '.git'))
                print(f"Найден git репозиторий: {git_dir}")
                return git_dir
                
            parent_dir = os.path.dirname(current_dir)
            if parent_dir == current_dir:  # Достигли корня файловой системы
                print("Не удалось найти git репозиторий.")
                return None
                
            current_dir = parent_dir
            print(f"Проверяем директорию: {current_dir}")
            
    except Exception as e:
        print(f"Ошибка при поиске git репозитория: {e}")
        return None
    finally:
        # Возвращаемся в исходную директорию
        os.chdir(INITIAL_DIR)

def find_tag(tag_pattern):
    # Проверяем текущую директорию. Если не initial_dir, то переходим в нее
    if os.getcwd() != INITIAL_DIR:
        os.chdir(INITIAL_DIR)
    # Переходим в директорию с git репозиторием
    git_dir = find_git_repository()
    if git_dir is None:
        print("Не удалось найти git репозиторий.")
        return None
    os.chdir(git_dir)
    # Получаем все теги в git репозитории
    all_tags = os.popen('git tag').read().strip().split('\n')
    if not all_tags:
        print("Не найдено ни одного тега в git репозитории.")
        return None
    # Фильтруем теги по заданному шаблону
    matching_tags = [tag for tag in all_tags if tag_pattern in tag]
    if not matching_tags:
        print(f"Не найдено тегов, соответствующих шаблону: {tag_pattern}")
        return None
    # Получаем последний тег из списка совпадений
    latest_tag = matching_tags[-1]
    print(f"Найден тег: {latest_tag}")
    # Возвращаемся в исходную директорию
    os.chdir(os.path.dirname(INITIAL_DIR))
    return latest_tag

def merge_bins ():
    #  Пути к файлам
    os.chdir(INITIAL_DIR)
    pwd = os.getcwd()
    file_path_working = os.path.join(INITIAL_DIR, "SB_TMSG44V1_WORKING_FPGA.bin")
    file_path_golden = os.path.join(INITIAL_DIR, "SB_TMSG44V1_GOLD_FPGA.bin")
    file_path_output = os.path.join(INITIAL_DIR, "SB_TMSG44V1_TEST_MERGE_FPGA.bin")
    #  Размеры файлов
    file_size_working   = os.path.getsize(file_path_working)
    file_size_golden    = os.path.getsize(file_path_golden)
    #  Размер выходного файла - 8 Мбит
    file_size_output    = 0x1000000  
    # Записываем первый файл
    with open(file_path_output,'wb') as outfile:
        with open(file_path_working, 'rb') as f1:
            shutil.copyfileobj(f1, outfile)
        # Перемещаемся к адресу для второго файла
        outfile.seek(GOLDEN_ADDRESS)
        with open(file_path_golden, 'rb') as f2:
            shutil.copyfileobj(f2, outfile)
        # Перемещаемся к адресу для пользовательских данных
        outfile.seek(APP_VER_ADDRESS)
        current_git_tag=find_tag("_WORKING")
        print(f"Текущий git tag: {current_git_tag}")
        # Если полученный тег меньше 32 байт, то дополняем его до 32 байт
        encoded_git_tag = current_git_tag.encode('utf-8')
        if len(encoded_git_tag) < 32:
            encoded_git_tag = encoded_git_tag.ljust(32, b'\x00')

        # Записываем тег в файл
        outfile.write(encoded_git_tag)
        # Перемещаемся к адресу для GOLDEN данных
        outfile.seek(GOLDEN_APP_VER_ADDRESS)
        golden_tag = find_tag("_GOLDEN")
        print(f"Текущий golden git tag: {golden_tag}")
        # Если полученный тег меньше 32 байт, то дополняем его до 32 байт
        encoded_golden_tag = golden_tag.encode('utf-8')
        if len(encoded_golden_tag) < 32:
            encoded_golden_tag = encoded_golden_tag.ljust(32, b'\x00')
        outfile.write(encoded_golden_tag)
    final_size = os.path.getsize(file_path_output)
    # Проверка итогового размера
    if final_size > file_size_output:
        os.remove(file_path_output)  # Удаляем некорректный файл
        raise ValueError(f"Итоговый размер файла ({final_size} байт) превысил максимально допустимый ({file_size_output} байт)")
    print(f"Размер файла 1: {file_size_working} байт")
    print(f"Размер файла 2: {file_size_golden} байт")
    print(f"Итоговый размер: {final_size} байт")
    return final_size

def merge_working_only():
    #  Пути к файлам
    os.chdir(INITIAL_DIR)
    pwd = os.getcwd()
    file_path_working = os.path.join(INITIAL_DIR, "SB_TMSG44V1_WORKING_FPGA.bin")
    file_path_output = os.path.join(INITIAL_DIR, "SB_TMSG44V1_TEST_WORKING_FPGA.bin")
    #  Размеры файлов
    file_size_working   = os.path.getsize(file_path_working)
    #  Размер выходного файла - 8 Мбит
    file_size_output    = 0x1000000  
    # Записываем первый файл
    with open(file_path_output,'wb') as outfile:
        with open(file_path_working, 'rb') as f1:
            shutil.copyfileobj(f1, outfile)
        # Перемещаемся к адресу для пользовательских данных
        outfile.seek(APP_VER_ADDRESS)
        current_git_tag=find_tag("_WORKING")
        print(f"Текущий git tag: {current_git_tag}")
        # Если полученный тег меньше 32 байт, то дополняем его до 32 байт
        encoded_git_tag = current_git_tag.encode('utf-8')
        if len(encoded_git_tag) < 32:
            encoded_git_tag = encoded_git_tag.ljust(32, b'\x00')

        # Записываем тег в файл
        outfile.write(encoded_git_tag)
    final_size = os.path.getsize(file_path_output)
    # Проверка итогового размера
    if final_size > file_size_output:
        os.remove(file_path_output)  # Удаляем некорректный файл
        raise ValueError(f"Итоговый размер файла ({final_size} байт) превысил максимально допустимый ({file_size_output} байт)")
    print(f"Размер файла: {file_size_working} байт")
    print(f"Итоговый размер: {final_size} байт")
    return final_size

def merge_test_only():
    #  Пути к файлам
    os.chdir(INITIAL_DIR)
    pwd = os.getcwd()
    file_path_test = os.path.join(INITIAL_DIR, "SB_TMSG44V1_FPGA_TEST.bin")
    file_path_output = os.path.join(INITIAL_DIR, "SB_TMSG44V1_TEST_FPGA.bin")
    #  Размеры файлов
    file_size_test   = os.path.getsize(file_path_test)
    #  Размер выходного файла - 8 Мбит
    file_size_output    = 0x1000000  
    # Записываем первый файл
    with open(file_path_output,'wb') as outfile:
        with open(file_path_test, 'rb') as f1:
            shutil.copyfileobj(f1, outfile)
        # Перемещаемся к адресу для пользовательских данных
        outfile.seek(APP_VER_ADDRESS)
        test_tag = find_tag("_TEST")
        print(f"Текущий test git tag: {test_tag}")
        # Если полученный тег меньше 32 байт, то дополняем его до 32 байт
        encoded_test_tag = test_tag.encode('utf-8')
        if len(encoded_test_tag) < 32:
            encoded_test_tag = encoded_test_tag.ljust(32, b'\x00')
        # Записываем тег в файл
        outfile.write(encoded_test_tag)
    final_size = os.path.getsize(file_path_output)
    # Проверка итогового размера
    if final_size > file_size_output:
        os.remove(file_path_output)  # Удаляем некорректный файл
        raise ValueError(f"Итоговый размер файла ({final_size} байт) превысил максимально допустимый ({file_size_output} байт)")
    print(f"Размер файла: {file_size_test} байт")
    print(f"Итоговый размер: {final_size} байт")
    return final_size


def merge_golden_only():
    #  Пути к файлам
    os.chdir(INITIAL_DIR)
    pwd = os.getcwd()
    file_path_golden = os.path.join(INITIAL_DIR, "SB_TMSG44V1_GOLD_FPGA.bin")
    file_path_output = os.path.join(INITIAL_DIR, "SB_TMSG44V1_TEST_GOLDEN_FPGA.bin")
    #  Размеры файлов
    file_size_golden   = os.path.getsize(file_path_golden)
    #  Размер выходного файла - 8 Мбит
    file_size_output    = 0x1000000  
    # Записываем первый файл
    with open(file_path_output,'wb') as outfile:
        with open(file_path_golden, 'rb') as f2:
            shutil.copyfileobj(f2, outfile)
        # Перемещаемся к адресу для пользовательских данных
        outfile.seek(GOLDEN_APP_VERSION_SHIFTED)
        golden_tag = find_tag("_GOLDEN")
        print(f"Текущий golden git tag: {golden_tag}")
        # Если полученный тег меньше 32 байт, то дополняем его до 32 байт
        encoded_golden_tag = golden_tag.encode('utf-8')
        if len(encoded_golden_tag) < 32:
            encoded_golden_tag = encoded_golden_tag.ljust(32, b'\x00')
        outfile.write(encoded_golden_tag)
    final_size = os.path.getsize(file_path_output)
    # Проверка итогового размера
    if final_size > file_size_output:
        os.remove(file_path_output)  # Удаляем некорректный файл
        raise ValueError(f"Итоговый размер файла ({final_size} байт) превысил максимально допустимый ({file_size_output} байт)")
    print(f"Размер файла: {file_size_golden} байт")
    print(f"Итоговый размер: {final_size} байт")
    return final_size


def main():

    parser = argparse.ArgumentParser(description='Скрипт для объединения бинарных файлов прошивок')
    parser.add_argument('--mode', choices=['merge', 'working', 'golden'], 
                        help='Режим работы: merge - объединить Working и Golden, working - только Working и  Working версию, golden - только Golden и Golden версию',
                        required=False)
    
    args = parser.parse_args()
    
    # Если режим не задан через аргумент, запрашиваем у пользователя
    if args.mode is None:
        print("Выберите режим работы:")
        print("1. merge   - объединить Working и Golden прошивки")
        print("2. working - объединить только Working прошивку с её версией")
        print("3. golden  - объединить только Golden прошивку с её версией")
        print("4. test    - объединить только Test прошивку с её версией")
        
        choice = ""
        while choice not in ["1", "2", "3","4", "merge", "working", "golden","test"]:
            choice = input("Введите номер (1-4) или название режима: ").strip().lower()
            if choice == "1":
                choice = "merge"
            elif choice == "2":
                choice = "working"
            elif choice == "3":
                choice = "golden"
            elif choice == "4":
                choice = "test"
        
        mode = choice
    else:
        mode = args.mode
    
    if mode == 'merge':
        print("Объединение Working и Golden прошивок...")
        merge_bins()
    elif mode == 'working':
        print("Объединение только Working прошивки с её версией...")
        merge_working_only()
    elif mode == 'golden':
        print("Объединение только Golden прошивки с её версией...")
        merge_golden_only()
    elif mode == 'test':
        print("Объединение только Test прошивки с её версией...")
        merge_test_only()



if __name__ == '__main__':
    main()