from .services.base_service import Base_service
import sys
import os
import re
from py_module.whiptail import Whiptail
import py_module.yaml as yaml
import py_module.docker as docker
import py_module.jinja2 as jinja
import subprocess
import string
import secrets
import uuid
import hashlib
from .docker_installer import Docker_installer
from .services import *
from .services import base_service


class Media_install(Base_service):
    def preload(self):
        with Docker_installer(logger_level = self.logger_level) as run:
            pass
        self.logger.info('Инициализирую основные переменные')

        if not self.DETALIZATION:
            self.DETALIZATION = 1
        self.INSTALL_DUMP_PATH='./images'
        self.INSTALL_CONF_PATH='./configs_media'
        self.BACK_MENU=[False]

### ENVIRONMENT GERENAL
        self.DETALIZATION = 1

### ENVIRONMENT TEAM

        self.dockercli = docker.from_env();

        self.menu = (
            ('media-opensips','media: Служба opensips','ON'),
            ('media-nginx','media: Служба nginx','ON'),
            ('media-media','Р7-ДС: MQTT-служба очередей','ON'),
            ('media-xcoder','Р7-ДС: Сервер кэширования','ON'),
            ('media-redis','media: Служба redis','ON'),
            ('media-media-db','media: Служба media db','ON')
        );
        self.PREFIX_MAIL=['mail']
        self.PREFIX_TEAM=['team']
### ENVIRONMENT MEDIA
        self.MEDIA_FQDN=['media.domain.ru']
        self.MEDIA_CERT_CRT_PATH=['./configs/ssl']
        self.MEDIA_CERT_CRT_FILE=['fullchain.crt']
        self.MEDIA_CERT_KEY_PATH=['./configs/ssl']
        self.MEDIA_CERT_KEY_FILE=['privkey.key']
        self.MEDIA_HTTPS_PUBLISH_PORT=['443']
        self.MEDIA_HTTP_PUBLISH_PORT=['80']
        self.MEDIA_UUID=['далее последует три параметра']
        self.MEDIA_TOKEN=['token']
        self.MEDIA_HASH=['hash']
        
### ENVIRONMENT MEDIA-OPENSIPS        
        self.MEDIA_OPENSIPS_PORT=['5060']
        self.MEDIA_OPENSIPS_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/media/opensips']
        self.MEDIA_OPENSIPS_IMAGE_VERSION=['2.4']
        self.MEDIA_OPENSIPS_CONTAINER_NAME=['media-opensips']
        self.MEDIA_OPENSIPS_HOST=['opensips']
### ENVIRONMENT MEDIA-OPENSIPS        

### ENVIRONMENT MEDIA-REDIS        
        self.MEDIA_REDIS_PORT=['6379']
        self.MEDIA_REDIS_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/team/astra/ubi18-redis']
        self.MEDIA_REDIS_IMAGE_VERSION=['7.4.1']
        self.MEDIA_REDIS_CONTAINER_NAME=['media-redis']
        self.MEDIA_REDIS_HOST=['redis']
### ENVIRONMENT MEDIA-REDIS        

### ENVIRONMENT MEDIA-NGINX        
        self.MEDIA_NGINX_PORT=['']
        self.MEDIA_NGINX_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/media/nginx']
        self.MEDIA_NGINX_IMAGE_VERSION=['2.4']
        self.MEDIA_NGINX_CONTAINER_NAME=['media-nginx']
        self.MEDIA_NGINX_HOST=['nginx']
### ENVIRONMENT MEDIA-NGINX        

### ENVIRONMENT MEDIA-MEDIA-DB        
        self.MEDIA_MEDIA_DB_PORT=['']
        self.MEDIA_MEDIA_DB_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/media/media-db']
        self.MEDIA_MEDIA_DB_IMAGE_VERSION=['2.52']
        self.MEDIA_MEDIA_DB_CONTAINER_NAME=['media-media-db']
        self.MEDIA_MEDIA_DB_HOST=['media-db']
### ENVIRONMENT MEDIA-MEDIA-DB        

### ENVIRONMENT MEDIA-MEDIA        
        self.MEDIA_MEDIA_PORT=['']
        self.MEDIA_MEDIA_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/media/media']
        self.MEDIA_MEDIA_IMAGE_VERSION=['2.52']
        self.MEDIA_MEDIA_CONTAINER_NAME=['media-media']
        self.MEDIA_MEDIA_HOST=['media']
### ENVIRONMENT MEDIA-MEDIA        

### ENVIRONMENT MEDIA-XCODER        
        self.MEDIA_XCODER_PORT=['']
        self.MEDIA_XCODER_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/media/xcoder']
        self.MEDIA_XCODER_IMAGE_VERSION=['5.18.0']
        self.MEDIA_XCODER_CONTAINER_NAME=['media-xcoder']
        self.MEDIA_XCODER_HOST=['xcoder']
### ENVIRONMENT MEDIA-XCODER        

        self.select_components=None
        self.dockercli = docker.from_env();

        self.services = {}
        for service in self.menu:
            getattr(self,"services")[service[0].replace('-','_')] = getattr(globals()[service[0].replace('-','_')], service[0].replace('-','_'))


        self.components={};

        self.compose={
#            'version':'3.3',
#            'name': 'cddisk',
            'services': {},
            'networks': {
                'external': {},
                'internal': {},
            },
            'volumes': {
                'icc': {},
                'recordings':{},
                'media-db': {},
                'media-log': {},
                'xcoder-log': {},
            }
        };
        self.select_components=None
        self.dockercli = docker.from_env();

    def postload(self, **kwarg):
        self.get_service()
#        self.get_requests(**kwarg);
        if self.BACK_MENU[0]==True:
            return        
        self.load_images(['xcoder.tar.gz','ubi18-redis.tar.gz','opensips.tar.gz','nginx.tar.gz','media.tar.gz','media-db.tar.gz']);

        base_ser = base_service.Base_service()
        test=base_ser.status_dns(f"{self.MEDIA_FQDN[-1]}")
        test2=base_ser.status_ram(8)
        test3=base_ser.status_proc(4)
#        test4=base_ser.status_host_port(self)
        test5=base_ser.status_hdd()
        self.build_compose();
        if self.form.yesno(test+test2+test3, default="yes"):
            if self.form.yesno(test5, default="yes"):
                self.build_configs()
                self.deploy()
            else:
                return
        else:
            return
        return self;        


    def load_images(self, images: list = []):
        outputs=[];
        self.logger.info(f'Начинаю импорт дампа образов: {images}')
        for image in images:
            self.logger.debug(f'Открываю файл дампа: {self.INSTALL_DUMP_PATH}/{image}')
            if os.path.isfile(f'{self.INSTALL_DUMP_PATH}/{image}'):
                with open(f'{self.INSTALL_DUMP_PATH}/{image}', 'rb') as file:
                    print(f'\nЗагружаю dump образов:\n{sys.path[0]}/images/{image}\n');
                    self.logger.info(f'Загружаю dump образов: {self.INSTALL_DUMP_PATH}/{image}')
                    try:
                        outputs = outputs + self.dockercli.images.load(file);
                    except:
                        self.logger.error(f'Произошла ошибка при загрузке docker-образов из dump-файла: {image}')
                        return self.msgbox(f'Произошла ошибка при загрузке docker-образов из dump-файла {image}.');
            else:
                self.logger.error(f'Файл dump образов отсутствует: {self.INSTALL_DUMP_PATH}/{image}')

#    def load_images(self, images: list = []):
#        outputs=[];
#        for image in images:
#            with open(f'{sys.path[0]}/images/{image}', 'rb') as file:
#                print(f'\nЗагружаю dump образов:\n{sys.path[0]}/images/{image}\n');
#                try:
#                    outputs = outputs + self.dockercli.images.load(file);
#                except:
#                    self.msgbox(f'Произошла ошибка при загрузке docker-образов из dump-файла {image}');

    def uuid_gen(self):
#        def func(response, env):        
        self.MEDIA_UUID[0]=str(uuid.uuid4())
        self.msgbox(f'Ваш UUID:\n{self.MEDIA_UUID[-1]}')
        characters = string.ascii_letters + string.digits
        TEMP_PWD = ''.join(secrets.choice(characters) for _ in range(100))
        self.MEDIA_TOKEN.append(TEMP_PWD)
        self.msgbox(f'Ваш TOKEN:\n{self.MEDIA_TOKEN[-1]}')
        hash_obj = hashlib.sha512()
        hash_obj.update(TEMP_PWD.encode())
        self.MEDIA_HASH.append(hash_obj.hexdigest())
        self.msgbox(f'Ваш TOKEN HASH:\n{self.MEDIA_HASH[-1]}')
#            return True, f'Сохраните значение {self.MEDIA_UUID[-1]}'
        return True, None

#        return func
    def get_service(self, exit_target = None):
        if self.DETALIZATION > 2:# and self.DETALIZATION < 6:
            self.logger.info('Вывожу запрос у пользователя списка устанавливаемых компонентов.')
            self.response = self.form.checklist(msg = 'Выберите устанавливаемые компоненты:', items = self.menu);
        else:
            self.response = ([
                'media-opensips',
                'media-redis',
                'media-nginx',
                'media-media-db',
                'media-media',
                'media-xcoder'
                ], 0);
        if not self.response[1]:
            self.select_components = self.response[0];
            self.logger.info(f'Выбраны компоненты: {self.select_components}')
#            print (self.select_components);
            for item in self.select_components:
                print(item)
                self.logger.info(f'Вызываю модуль: {item.replace("-","_")}.py')
                with self.services[item.replace('-','_')](**dict(filter(lambda item: item[0]==item[0].upper(), vars(self).items())), select_components = self.select_components, logger_level = self.logger_level) as run:
                    run.go();
                    if self.BACK_MENU[0]==True:
                        return        
                    for name, value in run.get_constants().items():
                        setattr(self, name, value);
#                    print(run.get_service())
                    self.components.update(run.get_service())
        return self;

    def build_compose(self):
        self.compose['services'] = self.components;
        self.logger.info(f'Открываю compose-файл media-compose.yaml на запись')
        with open('media-compose.yaml', 'w') as f:
            self.logger.info(f'Выгружаю compose-файл media-compose.yaml')
            yaml.dump(self.compose, f, sort_keys=False);
            
    def build_configs(self):
        self.uuid_gen()
        self.logger.info(f'Произвожу поиск файлов-шаблонов конфигураций')
        for root, dirs, files in os.walk(self.INSTALL_CONF_PATH):
            for file in files:
                if file.endswith('.j2'):
                    self.logger.info(f'Вызываю шаблонизатор Jinja2 на файл {root}/{file}')
                    env = jinja.Environment(loader=jinja.FileSystemLoader([root]))
                    template = env.get_template(file);
                    self.logger.info(f'Открываю файл {root}/{file.replace(".j2", "")} на запись.')
                    with open(f'{root}/{file.replace(".j2", "")}', 'w') as f:
                        self.logger.info(f'Произвожу рендеринг шаблона и экспорт в файл')
                        f.write(template.render(self.__dict__));
                        self.logger.info(f'Файл {root}/{file.replace(".j2", "")} создан.')

    def deploy(self):
        print (f'\n\nИзменяю параметры контейнеров.\n\n############\n#### ВНИМАНИЕ: НЕ ОСТАНАВЛИВАЙТЕ ПРОЦЕСС\n############\n\n');

        command = [f'{sys.path[0]}/runtime/docker/docker', 'compose', '--project-name', 'media','-f', f'{sys.path[0]}/media-compose.yaml', 'up', '-d', '-V']#, '--remove-orphans']#'--force-recreate', '-d', '-V', '--remove-orphans']
        result = subprocess.run(command)
        if result.returncode != 0:
            self.logger.error(f'При попытке запуска команды ({command}) произошли ошибки')
            self.logger.error(result.stderr)
            self.msgbox(f'Установка не выполнена. Обратитесь в техподдержку Р7-Офис')
        else:
            self.logger.debug(result.stdout)
            self.logger.info('Docker Compose Plugin завершился без ошибок.')
            self.msgbox(f'Медиа сервер установлен\nВаши UUID, ваш TOKEN и ваша TOKEN-HASH-сумма будут автоматически сохранены в файле {self.INSTALL_CONF_PATH}/token');
