import sys
import os
#from threading import Thread
#from queue import Queue, Empty

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
#from .services.base_service import Base_service
from .base import Base
from .docker_installer import Docker_installer
from .services import *

class Ins_Ds_Docserver(Base):
    def preload(self):
        with Docker_installer(logger_level = self.logger_level) as run:
            pass
        self.menu = (
            ('ds-docserver','Р7-ДС: Служба документ-сервера','ON'),
        );
#        self.services = {}
#        for service in self.menu:
#            getattr(self,"services")[service[0].replace('-','_')] = getattr(globals()[service[0].replace('-','_')], service[0].replace('-','_'))()

#            setattr(self, "class_" + service[0].replace('-','_'), getattr(globals()[service[0].replace('-','_')], service[0].replace('-','_'))())
#        dumper.dump(vars(self));

        self.logger.info('Инициализирую основные переменные')
##########################################################################
##            DEFAULT ENVIRONMENT FOR INSTALLATION                      ##
##                                                                      ##
##       self.ENV_NAME = list(default_value, select_value)              ##
##                                                                      ##
##########################################################################

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

##########################################################################
##            DEFAULT ENVIRONMENT FOR IMAGE DOCKER                      ##
##                                                                      ##
##       self.ENV_NAME = list(default_value, select_value)              ##
##                                                                      ##
##########################################################################

### ENVIRONMENT GERENAL
#        self.DETALIZATION = 1
#        self.CS_VERSION=['latest']
        self.CS_VERSION=['2025.3.12.15877']
#        self.DS_VERSION=['latest']
        self.DS_VERSION=['2025.3.1.923']
        self.MAIL_VERSION=['1.0.35-swarm']
        self.PREFIX_CS=['cs']
        self.PREFIX_DS=['ds']
        self.PREFIX_MAIL=['mail']
        self.PREFIX_TEAM=['team']

#        self.NODE_FRONTEND_CERT_WILDCARD
        self.GENERAL_NODE_LOGS_STORAGE=['./support_logs','./support_logs']


        self.DS_NODE_PSQL_STORAGE=['./data/db/ds_database','./data/db/ds_database']
        self.DS_NODE_FILE_STORAGE=['./data/ds_storage']
        self.DS_NODE_LICENSE_FILE=['./license/license.lic']

#env for published port of services on node

        self.DS_NODE_DOCSERVER_PORT_PUBLISHED=['8000']
        self.DS_NODE_RABBIT_PORT_PUBLISHED=['5673']
        self.DS_NODE_PSQL_PORT_PUBLISHED=['5433']
        self.DS_NODE_REDIS_PORT_PUBLISHED=['6379']


### ENVIRONMENT CS
#env for frontend
        self.CS_FRONTEND_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/cs/cddisk-frontend']
        self.CS_FRONTEND_IMAGE_VERSION=[self.CS_VERSION[0]]
        self.CS_FRONTEND_CONTAINER_NAME=['cs-frontend']

        self.CS_FRONTEND_HOST=['cs-frontend']
        self.CS_FRONTEND_SCHEME=['https']
        self.CS_FRONTEND_SCHEME_REDIRECT=[True]
        self.CS_FRONTEND_DOMAIN=['domain.ru']
        self.CS_FRONTEND_HTTP_PORT=['80']
        self.CS_FRONTEND_HTTPS_PORT=['443']
        self.CS_FRONTEND_PREFIX_CDDISK=['disk','disk']
        self.CS_FRONTEND_PREFIX_PAYMENTS=['payments','payments']
        self.CS_FRONTEND_PREFIX_PAGES=['pages']
        self.CS_FRONTEND_PREFIX_FORMS=['forms']
        self.CS_FRONTEND_PREFIX_DRAW=['draw','draw']
        self.CS_FRONTEND_PREFIX_ADMIN=['admin','admin']
        self.CS_FRONTEND_PREFIX_CDMAIL=['mail','mail']
        self.CS_FRONTEND_PREFIX_CONTACTS=['contacts','contacts']
        self.CS_FRONTEND_PREFIX_CALENDAR=['calendar','calendar']
        self.CS_FRONTEND_PREFIX_PROJECTS=['projects','projects']
        self.CS_FRONTEND_STORAGE=['/app']
        self.CS_FRONTEND_CERT_PATH=['/etc/nginx/ssl']
        self.CS_FRONTEND_CERT_CRT_FILE=['fullchain.crt']
        self.CS_FRONTEND_CERT_KEY_FILE=['privkey.key']
#env for rabbit
        self.CS_RABBIT_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/cs/cddisk-rabbitmq']
        self.CS_RABBIT_IMAGE_VERSION=[self.CS_VERSION[0]]
        self.CS_RABBIT_CONTAINER_NAME=['cs-rabbitmq']

        self.CS_RABBIT_HOST=['cs-rabbit']
        self.CS_RABBIT_USER=['guest']
        self.CS_RABBIT_PWD=['guest']
        self.CS_RABBIT_PORT=['5672']
        self.CS_RABBIT_CLIENT_TIMEOUT=['10']
#env for psql
        self.CS_PSQL_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/cs/cddisk-postgres']
        self.CS_PSQL_IMAGE_VERSION=[self.CS_VERSION[0]]
        self.CS_PSQL_CONTAINER_NAME=['cs-psql']

#env for api and processing
        self.CS_STORAGE_S3_REGION=['region']
        self.CS_STORAGE_S3_ENDPOINT=['http://localhost/s3']
        self.CS_STORAGE_S3_BUCKET_NAME=['ds-storage']
        self.CS_STORAGE_S3_ACCESS_KEY_ID=['AKID2']
        self.CS_STORAGE_S3_SECRET_ACCESS_KEY=['SECRET']
#env for processing

### ENVIRONMENT DS
#env for frontend
        self.DS_FRONTEND_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/ds/ds-frontend']
        self.DS_FRONTEND_IMAGE_VERSION=[self.DS_VERSION[0]]
        self.DS_FRONTEND_CONTAINER_NAME=['ds-frontend']

        self.DS_FRONTEND_HOST=['ds-frontend']
        self.DS_FRONTEND_PREFIX_DOCSERVER=['doc']
        self.DS_FRONTEND_SCHEME=self.CS_FRONTEND_SCHEME
        self.DS_FRONTEND_SCHEME_REDIRECT=self.CS_FRONTEND_SCHEME_REDIRECT
        self.DS_FRONTEND_DOMAIN=self.CS_FRONTEND_DOMAIN
        self.DS_FRONTEND_HTTP_PORT=['80']
        self.DS_FRONTEND_HTTPS_PORT=['443']
#env for docserver
        self.DS_DOCSERVER_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/ds/ds-app']
        self.DS_DOCSERVER_IMAGE_VERSION=[self.DS_VERSION[0]]
        self.DS_DOCSERVER_CONTAINER_NAME=['ds-docserver']

        self.DS_DOCSERVER_HOST=['ds-docserver']
        self.DS_DOCSERVER_PORT=['8000']
        self.DS_DOCSERVER_JWT_KEY=['empty']
        self.DS_DOCSERVER_STORAGE_KEY=self.DS_DOCSERVER_JWT_KEY
#env for docserver over s3
        self.DS_STORAGE_S3_REGION=['region']
        self.DS_STORAGE_S3_ENDPOINT=['http://localhost/s3']
        self.DS_STORAGE_S3_BUCKET_NAME=['ds-storage']
        self.DS_STORAGE_S3_ACCESS_KEY_ID=['AKID2']
        self.DS_STORAGE_S3_SECRET_ACCESS_KEY=['SECRET']
#env for rabbit
        self.DS_RABBIT_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/ds/ds-rabbitmq']
        self.DS_RABBIT_IMAGE_VERSION=[self.DS_VERSION[0]]
        self.DS_RABBIT_CONTAINER_NAME=['ds-rabbitmq']

        self.DS_RABBIT_HOST=['ds-rabbit']
        self.DS_RABBIT_USER=['guest']
        self.DS_RABBIT_PWD=['guest']
        self.DS_RABBIT_PORT=['5672']
#env for psql
        self.DS_PSQL_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/ds/ds-postgres']
        self.DS_PSQL_IMAGE_VERSION=[self.DS_VERSION[0]]
        self.DS_PSQL_CONTAINER_NAME=['ds-postgres']

        self.DS_PSQL_HOST=['ds-psql']
        self.DS_PSQL_DB=['postgres']
        self.DS_PSQL_USER=['postgres']
        self.DS_PSQL_PWD=['pg_pass']
        self.DS_PSQL_PORT=['5432']
#env for redis
        self.DS_REDIS_IMAGE_NAME=['downloads.r7-office.ru:9011/r7office/ds/ds-redis']
        self.DS_REDIS_IMAGE_VERSION=[self.DS_VERSION[0]]
        self.DS_REDIS_CONTAINER_NAME=['ds-redis']

        self.DS_REDIS_HOST=['ds-redis']
        self.DS_REDIS_PORT=['6379']

### ENVIRONMENT DS


### ENVIRONMENT TEAM
#env for rabbit

        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': {
                'net-ds': {
                    'name': f'net-{self.PREFIX_DS[0]}',
                    'driver': 'bridge',
                    'attachable': 'true'
                },
            },
            "volumes": {
                'ds-www': {}
            }
        };
        self.select_components=None
        self.dockercli = docker.from_env();

    def postload(self):
        self.get_service();
        if self.BACK_MENU[0]==True:
            return
        self.load_images(['ds-app.tar.gz']);
#        self.get_parameters(exit_target = self.exit_target);
        self.build_compose();
        self.build_configs();
        self.deploy();
        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 get_service(self, exit_target = None):
        self.response = ([
            'ds-docserver',
            ], 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):
        del self.components['ds-docserver']['depends_on']
        self.components['ds-docserver']['ports']=[
            {'target': 8000,
            'published': self.DS_DOCSERVER_PORT[-1],
            'protocol': 'tcp',
            'mode': 'host'}
        ]
        self.compose['services'] = self.components;
        self.logger.info(f'Открываю compose-файл ds_docserver.yaml на запись')
        with open('ds_docserver.yaml', 'w') as f:
            self.logger.info(f'Выгружаю compose-файл ds_docserver.yaml')
            yaml.dump(self.compose, f);

    def build_configs(self):
        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-plugins/docker-compose', '-f', f'{sys.path[0]}/ds_docserver.yaml', 'up', '--force-recreate', '-d', '-V']#, '--remove-orphans']
        return_code, stdout, stderr = self.subprocess(command, fd_stderr=sys.stdout)
        if return_code != 0:
            self.logger.error(f'При попытке запуска команды ({command}) произошли ошибки')
            for err in stderr: self.logger.error(err) if 'error' in err.lower() else self.logger.info(err)
            self.msgbox(f'Установка не удалась. Обратитесь в техподдержку Р7-Офис')
        else:
            for err in stderr: self.logger.debug(err)
            self.logger.info('Docker Compose Plugin завершился без ошибок.')
            self.msgbox(f'Установка сервиса завершена.\n{self.response[0]}')
