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
from .docker_installer import Docker_installer
from .services import *


class Team_Integration(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'
        self.BACK_MENU=[False]

### ENVIRONMENT GERENAL
        self.DETALIZATION = 1

### ENVIRONMENT TEAM
#env for rabbit
        self.TEAM_FQDN=['team.domain.ru']
        self.TEAM_RABBIT_HOST=['team-rabbit']
        self.TEAM_RABBIT_USER=['team']
        self.TEAM_RABBIT_PWD=['team']
        self.TEAM_RABBIT_PORT=['5672']
        self.TEAM_RABBIT_PUBLISH_PORT=['5672']
        self.TEAM_HTTPS_PUBLISH_PORT=['443']
        self.TEAM_HTTP_PUBLISH_PORT=['80']
        self.dockercli = docker.from_env();
        self.CS_TEAM_CLIENT_ID=['']
        self.CS_TEAM_CLIENT_SECRET=['']
        self.CS_PAGES_CLIENT_ID=['']
        self.CS_PAGES_CLIENT_SECRET=['']
        self.CS_FORMS_CLIENT_ID=['']
        self.CS_FORMS_CLIENT_SECRET=['']

    def postload(self, **kwarg):
        self.get_requests(**kwarg);
        if self.BACK_MENU[0]==True:
            return        
        self.build_compose();
        self.deploy();
        return self;

    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}');
#        self.msgbox(f'''Загружены docker-образы:\n''' + [''.join(output.attrs["RepoTags"][0]+"""\n""") for output in outputs]);

    def build_compose(self):
        self.logger.info(f'Открываю compose-файл template.yaml на запись')

        with open('template.yaml', 'r') as file:
            compose_data = yaml.safe_load(file)

        if 'cs-rabbitmq' in compose_data['services']:
            if 'environment' not in compose_data['services']['cs-rabbitmq']:
                compose_data['services']['cs-rabbitmq']['environment'] = {}
            compose_data['services']['cs-rabbitmq']['environment']['r7_team_rabbit_pass'] = self.TEAM_RABBIT_PWD[-1]
            compose_data['services']['cs-rabbitmq']['ports'] = [{'mode': 'host', 'protocol': 'tcp', 'published': self.TEAM_RABBIT_PUBLISH_PORT[-1], 'target': self.TEAM_RABBIT_PORT[-1]}]
            compose_data['services']['cs-postgres']['environment']['r7_team_rabbit_pass'] = self.TEAM_RABBIT_PWD[-1]
        else:
            print(f"Сервис cs-rabbitmq не найден в template.yml")
        # Сохраняем изменения обратно в файл
        with open('template.yaml', 'w') as file:
            yaml.dump(compose_data, file, default_flow_style=False)

        print(f"Переменная окружения обновлена ")
        self.logger.info(f'Выгружаю compose-файл template.yaml')


    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]}/template.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 завершился без ошибок.')

        # Формируем SQL-запрос
#        SQL = 'UPDATE public."CustomerSettings" SET "Json" = CONCAT("TeamSettings":{ "IsEnabled":false,"Url":"", "ClientId":"", "ClientSecret":"", "RabbitData":{ "Name":"team","Password":"self.TEAM_RABBIT_PWD[-1]" }}) WHERE "CustomerId" = -1;'
        SQL1 = f"""UPDATE public."CustomerSettings"
                SET "Json" = CONCAT(
                '{{"TeamSettings":{{ "IsEnabled":true,"Url":"https://{self.TEAM_FQDN[-1]}:{self.TEAM_HTTPS_PUBLISH_PORT[-1]}?provider=r7disk", "ClientId":"", "ClientSecret":"", "RabbitData":{{ "Name":"team","Password":"{self.TEAM_RABBIT_PWD[-1]}" }}}}}}')
                WHERE "CustomerId" = -1;"""
        # SQL2 = f"""INSERT INTO public."AuthClients"("Name", "ClientId", "ClientSecret", "RedirectUrl", "ApplicationKey")
        #     VALUES('Команды', '12345678', '12345678', '', 'team')
        #     ON CONFLICT ("ApplicationKey") DO UPDATE
        #     SET "ClientId" = EXCLUDED."ClientId",
        #     "ClientSecret" = EXCLUDED."ClientSecret",
        #     "RedirectUrl" = EXCLUDED."RedirectUrl",
        #     "Name" = EXCLUDED."Name";"""
        # command = [
        #     'docker', 'exec', '-i', 'cs-psql',
        #     'psql', '-U', 'postgres', '-c', SQL2
        # ]
        command = [
            'docker', 'exec', '-i', 'cs-psql',
            'psql', '-U', 'postgres', '-c', SQL1
        ]

        result = subprocess.run(command, capture_output=True, text=True, check=True)
        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('Новые значения в PostgreSQL внесены.')
            self.msgbox(f'Настройки интеграции выполнены для Корпоративного сервера');
            self.logger.info('Изменения в контейнер cs-psql внесены')
    
    def get_requests(self, prefix_env: str = "CS", dialog: list = None, external:bool = False, **kwarg):
        dialogs = dialog if isinstance(dialog, list) else [
            {
                "env": f'TEAM_RABBIT_PWD',
                "enable": None,
                'msg': (
                    f'Настройка интеграции Корпоративный сервер Р7 -> Р7-Команда:\n\nВведите пароль пользователя {"внешнего " if external else ""}сервера RabbitMQ для интеграции с Р7-Команда',
                    f'Пароль пользователя {"внешнего " if external else ""}сервера RabbitMQ обязателен к заполнению.',
                    f'Пароль не может быть пустым или содержать символы, отличные от A-z, 0-9 и символы "_", "-"'
                ),
                "func_check": self.check_pwd(),
                "func_visibility": [self.visibility_detalization(), self.visibility_default()],
                "detalization": 1
            },
            # {
            #     "env": f'TEAM_RABBIT_PORT',
            #     "enable": None,
            #     "msg": (
            #         f'Корпоративный сервер Р7 -> Интеграция Р7 Команд:\n\nВведите номер порта в контейнере RabbitMQ для продукта Р7-{prefix_env}',
            #         f'Номер порта {"внешнего " if external else ""}сервера RabbitMQ обязателен к заполнению.',
            #         f'Номер порта {"внешнего " if external else ""}сервера RabbitMQ должен состоять из чисел, буквы и спецсимволы не допустимы.'
            #     ),
            #     "func_check": self.check_port(),
            #     "func_visibility": self.visibility_detalization(),
            #     "detalization": 1
            # },
            {
                "env": f'TEAM_RABBIT_PUBLISH_PORT',
                "enable": None,
                "msg": (
                    f'Настройка интеграции Корпоративный сервер Р7 -> Р7-Команда:\n\nВведите номер внешнего порта (порта хостовой машины) RabbitMQ для продукта Р7-{prefix_env}',
                    f'Номер порта {"внешнего " if external else ""}сервера RabbitMQ обязателен к заполнению.',
                    f'Номер порта {"внешнего " if external else ""}сервера RabbitMQ должен состоять из чисел, буквы и спецсимволы не допустимы.'
                ),
                "func_check": self.check_port(),
                "func_visibility": self.visibility_detalization(),
                "detalization": 1
            },
            {
                "env": f'TEAM_FQDN',
                "enable": None,
                "msg": (
                    f'Настройка интеграции Корпоративный сервер Р7 -> Р7-Команда:\n\nУкажите FQDN-имя для сервера управления Р7-Команда',
                    f'Имя FQDN обязательно к заполнению.',
                    f'Имя не может содержать спецсимволы, кроме "-"'
                ),
                "func_check": self.check_fqdn(),
                "func_visibility": [self.visibility_detalization()],
                "detalization": 1
            },
            {
                "env": f'TEAM_HTTPS_PUBLISH_PORT',
                "enable": None,
                "msg": (
                    f'Настройка интеграции Корпоративный сервер Р7 -> Р7-Команда:\n\nВведите номер HTTPS порта сервера управления Р7-Команда',
                    f'Номер порта обязателен к заполнению.',
                    f'Номер порта сервера должен состоять из чисел, буквы и спецсимволы не допустимы.'
                ),
                "func_check": self.check_port(),
                "func_visibility": self.visibility_detalization(),
                "detalization": 1
            },
            {
                "env": f'TEAM_HTTP_PUBLISH_PORT',
                "enable": None,
                "msg": (
                    f'Настройка интеграции Корпоративный сервер Р7 -> Р7-Команда:\n\nВведите номер HTTP порта сервера управления Р7-Команда',
                    f'Номер порта обязателен к заполнению.',
                    f'Номер порта сервера должен состоять из чисел, буквы и спецсимволы не допустимы.'
                ),
                "func_check": self.check_port(),
                "func_visibility": self.visibility_detalization(),
                "detalization": 1
            },                        
        ];
        self.get_dialogs(dialogs)
    
    def check_pwd(self):
        return lambda response, env: ((re.match(r'^[a-zA-Z_][a-zA-Z0-9_-]*$', response) and not response == ''), None)
