#!/usr/bin/env python3
import os
import shutil
import subprocess
import datetime
import logging

try:
    from colorama import init, Fore, Style
    init(autoreset=True)
except ImportError:
    class Dummy:
        def __getattr__(self, attr): 
            return ''
    Fore = Style = Dummy()
    def init(*args, **kwargs): 
        pass
    print("⚠ colorama не установлен, вывод будет не цветной.")

# === Утилита для вывода этапов ===
def step(message, status="progress"):
    symbols = {
        "progress": Fore.CYAN + "[→]" + Style.RESET_ALL,
        "success": Fore.GREEN + "[✔]" + Style.RESET_ALL,
        "error": Fore.RED + "[✘]" + Style.RESET_ALL,
        "warning": Fore.YELLOW + "[!]" + Style.RESET_ALL
    }
    print(f"{symbols.get(status, '[ ]')} {message}")
    getattr(logging, status if status in ['error', 'warning', 'info'] else 'debug')(message)

# === Пути и переменные ===
SCRIPT_DIRECTORY = os.path.dirname(os.path.abspath(__file__))
SCRIPT_CONFIGS_DIR = os.path.join(SCRIPT_DIRECTORY, 'configs')
SCRIPT_IMAGES_DIR = os.path.join(SCRIPT_DIRECTORY, 'images')
APP_DIR = '/opt/mint/logrotate'
LOG_DIR = '/opt/mint/logs'
BACKUP_DIR = os.path.join(APP_DIR, 'backup')
VERSION_FILE_SRC = os.path.join(SCRIPT_CONFIGS_DIR, 'version')
VERSION_FILE_DST = os.path.join(APP_DIR, 'version')
DOCKER_COMPOSE_SRC = os.path.join(SCRIPT_CONFIGS_DIR, 'docker-compose.yml')
DOCKER_COMPOSE_DST = os.path.join(APP_DIR, 'docker-compose.yml')
ENV_FILE_SRC = os.path.join(SCRIPT_CONFIGS_DIR, '.env')
ENV_FILE_DST = os.path.join(APP_DIR, '.env')

DOCKER_IMAGES = ['mint_logrotate']
CONTAINERS = ['mint_logrotate']
BASE_DIRS = [APP_DIR]

LOG_FILE = os.path.join(LOG_DIR, 'logrotate_setup.log')

# === Логирование ===
os.makedirs(LOG_DIR, exist_ok=True)
logging.basicConfig(filename=LOG_FILE, level=logging.INFO, format='%(asctime)s:%(levelname)s:%(message)s')

# === Основные классы ===
class FileManager:
    @staticmethod
    def update_env_file(env_file_dst, env_file_src):
        try:
            with open(env_file_dst, 'r') as file:
                current_lines = file.read().splitlines()
            with open(env_file_src, 'r') as file:
                template_lines = file.read().splitlines()

            current_vars = {}
            for line in current_lines:
                if '=' in line and not line.strip().startswith('#'):
                    key, value = line.split('=', 1)
                    current_vars[key] = value

            new_env = []
            for line in template_lines:
                if line.strip().startswith('#') or not line.strip():
                    new_env.append(line)
                elif '=' in line:
                    key, value = line.split('=', 1)
                    value = current_vars.get(key, value)
                    new_env.append(f"{key}={value}")

            with open(env_file_dst, 'w') as file:
                file.write("\n".join(new_env))
            step("Файл .env успешно обновлён", "success")
            return True
        except Exception as e:
            step(f"Ошибка обновления .env файла: {e}", "error")
            return False

    @staticmethod
    def create_directories():
        for d in BASE_DIRS:
            os.makedirs(d, exist_ok=True)
            step(f"Создана директория: {d}", "success")

    @staticmethod
    def ask_timezone_and_write_to_env(env_path):
        timezones = {
            '1': 'Europe/Kaliningrad',
            '2': 'Europe/Moscow',
            '3': 'Europe/Samara',
            '4': 'Asia/Yekaterinburg',
            '5': 'Asia/Omsk',
            '6': 'Asia/Krasnoyarsk',
            '7': 'Asia/Irkutsk',
            '8': 'Asia/Yakutsk',
            '9': 'Asia/Vladivostok',
            '10': 'Asia/Magadan',
            '11': 'Asia/Kamchatka'
        }

        while True:
            print("\nВыберите ваш часовой пояс:")
            for num, tz in timezones.items():
                print(f"{num}. {tz}")
            choice = input("Введите номер часового пояса: ").strip()
            if choice in timezones:
                tz = timezones[choice]
                try:
                    with open(env_path, 'r') as f:
                        lines = f.readlines()
                    updated = False
                    new_lines = []
                    for line in lines:
                        if line.startswith("TZ="):
                            new_lines.append(f"TZ={tz}\n")
                            updated = True
                        else:
                            new_lines.append(line)
                    if not updated:
                        new_lines.append(f"TZ={tz}\n")
                    with open(env_path, 'w') as f:
                        f.writelines(new_lines)
                    step(f"Выбран часовой пояс: {tz}", "success")
                    return
                except Exception as e:
                    step(f"Ошибка при записи часового пояса: {e}", "error")
                    return
            else:
                print("Неверный выбор. Попробуйте ещё раз.")

    @staticmethod
    def backup_files_and_images():
        bkp_day = datetime.datetime.now().strftime("%Y-%m-%d")
        bkp_dir = os.path.join(BACKUP_DIR, f'backup_{bkp_day}')
        os.makedirs(bkp_dir, exist_ok=True)
        step(f"Создана директория резервного копирования: {bkp_dir}", "success")

        for path in [ENV_FILE_DST, DOCKER_COMPOSE_DST, VERSION_FILE_DST]:
            if os.path.exists(path):
                shutil.copy2(path, bkp_dir)
                step(f"Скопирован: {path}", "success")

        for image in DOCKER_IMAGES:
            image_bkp = os.path.join(SCRIPT_IMAGES_DIR, f"{image}_bkp")
            orig = os.path.join(SCRIPT_IMAGES_DIR, image)
            if os.path.exists(orig):
                shutil.copy2(orig, image_bkp)
                step(f"Образ сохранён: {image_bkp}", "success")

class DockerManager:
    @staticmethod
    def upload_images():
        for image in DOCKER_IMAGES:
            image_path = os.path.join(SCRIPT_IMAGES_DIR, image)
            if os.path.exists(image_path):
                subprocess.run(['docker', 'load', '-i', image_path], check=True)
                step(f"Образ загружен: {image}", "success")

    @staticmethod
    def remove_old():
        for cont in CONTAINERS:
            subprocess.run(['docker', 'rm', '-f', cont], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        for image in DOCKER_IMAGES:
            subprocess.run(['docker', 'rmi', '-f', image], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        step("Удалены старые контейнеры и образы", "success")

class ContainerManager:
    @staticmethod
    def start():
        subprocess.run(['docker', 'compose', 'up', '-d'], cwd=APP_DIR, check=True)
        step("Контейнеры запущены", "success")

    @staticmethod
    def stop():
        subprocess.run(['docker', 'compose', 'stop'], cwd=APP_DIR, check=True)
        step("Контейнеры остановлены", "success")

# === Версия ===
def get_new_version():
    try:
        with open(VERSION_FILE_SRC, 'r') as f:
            return f.read().strip()
    except Exception:
        return "0.0.0"

def get_installed_version():
    try:
        with open(VERSION_FILE_DST, 'r') as f:
            return f.read().strip()
    except Exception:
        return "0.0.0"

# === Основной процесс ===
def main():
    new_version = get_new_version()
    installed = os.path.exists(VERSION_FILE_DST)

    print(Fore.MAGENTA + f"\n====== УСТАНОВКА/ОБНОВЛЕНИЕ MINT_LOGROTATE ======\nВерсия: {new_version}\n" + Style.RESET_ALL)

    if not installed:
        step("mint_logrotate не установлен. Начинаем установку...", "progress")
        FileManager.ask_timezone_and_write_to_env(ENV_FILE_SRC)
        FileManager.create_directories()
        DockerManager.upload_images()
        shutil.copy(ENV_FILE_SRC, ENV_FILE_DST)
        shutil.copy(DOCKER_COMPOSE_SRC, DOCKER_COMPOSE_DST)
        with open(VERSION_FILE_DST, 'w') as f:
            f.write(new_version)
        ContainerManager.start()
        step("Установка завершена", "success")
        return

    current_version = get_installed_version()
    
    if new_version > current_version:
        step(f"Обновление с версии {current_version} до {new_version}", "progress")
        ContainerManager.start()
        FileManager.backup_files_and_images()
        ContainerManager.stop()
        DockerManager.remove_old()
        DockerManager.upload_images()
        shutil.copy(DOCKER_COMPOSE_SRC, DOCKER_COMPOSE_DST)
        FileManager.update_env_file(ENV_FILE_DST, ENV_FILE_SRC)
        with open(VERSION_FILE_DST, 'w') as f:
            f.write(new_version)
        ContainerManager.start()
        step("Обновление завершено", "success")
    else:
        step(f"Установлена актуальная версия: {current_version}", "success")

# === Точка входа ===

if __name__ == '__main__':
    main()
