from .services.base_service import Base_service
import sys
import os
from py_module.whiptail import Whiptail
import py_module.yaml as yaml
import py_module.docker as docker
import py_module.jinja2 as jinja
from .docker_installer import Docker_installer
from .services import *


class Cert_Generator(Base_service):
    def preload(self):

        self.logger.info('Инициализирую основные переменные')

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

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

        self.GENERAL_NODE_LOGS_STORAGE=['./support_logs']

        self.CS_NODE_FRONTEND_CERT_CRT_PATH=['./configs/ssl']
        self.CS_NODE_FRONTEND_CERT_CRT_FILE=['fullchain.crt']
        self.CS_NODE_FRONTEND_CERT_KEY_PATH=['./configs/ssl']
        self.CS_NODE_FRONTEND_CERT_KEY_FILE=['privkey.key']

        self.CS_NODE_PSQL_STORAGE=['./data/db/cs_database']
        self.CS_NODE_FILE_STORAGE=['./data/cs_storage/root']
        self.CS_NODE_INDEX_STORAGE=['./data/search_index']

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

        self.MAIL_NODE_PSQL_STORAGE=['./data/db/mail_database']
        self.MAIL_NODE_MAILDIR_STORAGE=['./data/mail_storage/maildir']
        self.MAIL_NODE_DKIM_STORAGE=['./data/mail_storage/dkim_keys']

#env for published port of services on node

### ENVIRONMENT CS
#env for 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']
        self.CS_FRONTEND_PREFIX_PAYMENTS=['payments']
        self.CS_FRONTEND_PREFIX_PAGES=['pages']
        self.CS_FRONTEND_PREFIX_FORMS=['forms']
        self.CS_FRONTEND_PREFIX_DRAW=['draw']
        self.CS_FRONTEND_PREFIX_ADMIN=['admin']
        self.CS_FRONTEND_PREFIX_CDMAIL=['mail']
        self.CS_FRONTEND_PREFIX_CONTACTS=['contacts']
        self.CS_FRONTEND_PREFIX_CALENDAR=['calendar']
        self.CS_FRONTEND_PREFIX_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']
 
        self.CS_CERT_ORG=['Company']
        self.CS_CERT_ORG_UNIT=['Company Unit']


    def postload(self, **kwarg):

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

    def load_images(self, images: list = []):
        outputs=[];

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

    def build_configs(self):
        self.logger.info(f'Произвожу поиск файлов-шаблонов конфигураций')

    def deploy(self):

        root_key = f'{self.INSTALL_NEW_PATH[-1]}/ca-key.pem'
        root_cert = f'{self.INSTALL_NEW_PATH[-1]}/ca.pem'

        if os.path.exists(root_key):
            self.logger.info(f'Файл ключа {root_key} уже существует, генерация пропущена.')
        else:
            command = ['openssl', 'genrsa',  '-out', root_key, '2048']
            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)
                return self.msgbox(f'При генерации ключа корневого сертификата произошли ошибки. Обратитесь в службу технической поддержки Р7-офис.')
            else:
                for err in stderr: self.logger.debug(err)
                self.logger.info('Генерация ключа корневого сертификата без ошибок.')

        if os.path.exists(root_cert):
            self.logger.info(f'Файл сертификата {root_cert} уже существует, генерация пропущена.')
        else:
            tlscnf=f'/CN={self.CS_CERT_ORG_UNIT[-1]} CA/O={self.CS_CERT_ORG[-1]}/C=RU'
            command = ['openssl', 'req', '-x509', '-new', '-key', root_key, '-days', '10000', '-out', root_cert, '-subj', tlscnf]
            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)
                return self.msgbox(f'При генерации корневого сертификата произошли ошибки. Обратитесь в службу технической поддержки Р7-офис.')
            else:
                for err in stderr: self.logger.debug(err)
                self.logger.info('Генерация корневого сертификата без ошибок.')

        command = ['openssl', 'genrsa',  '-out', f'{self.INSTALL_NEW_PATH[-1]}/privkey.key', '2048']
        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('Генерация ключа конечного сертификата без ошибок.')
        content = f"""[req]
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[req_distinguished_name]
C = RU
ST = Russia
L = Russia
O = {self.CS_CERT_ORG[-1]}
OU = {self.CS_CERT_ORG_UNIT[-1]}
CN = www.{self.CS_FRONTEND_DOMAIN[-1]}

[req_ext]
keyUsage = keyEncipherment, dataEncipherment, digitalSignature
extendedKeyUsage = serverAuth
subjectAltName = @alt_names

[alt_names]
DNS.1 = *.{self.CS_FRONTEND_DOMAIN[-1]}
"""

        path=f'{self.INSTALL_NEW_PATH[-1]}/tls.cnf'
        try:
            dir = os.path.dirname(path)
            if dir:
                os.makedirs(dir, exist_ok=True)
            with open(path, 'w', encoding='utf-8') as f:
                f.write(content)
        except OSError as e:
            self.logger.error(f"Ошибка при создании или записи файла '{path}': {e}")
        except Exception as e:
            self.logger.error(f"Неожиданная ошибка: {e}")
        else:
            self.logger.info(f"Файл '{path}' успешно создан.")

        command = [f'openssl', 'req', '-new', '-sha256', '-out', f'{self.INSTALL_NEW_PATH[-1]}/cert.csr', '-key', f'{self.INSTALL_NEW_PATH[-1]}/privkey.key', '-config', f'{self.INSTALL_NEW_PATH[-1]}/tls.cnf']
        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('Генерация корневого сертификата без ошибок.')

        command = [f'openssl', 'x509', '-req', '-in', f'{self.INSTALL_NEW_PATH[-1]}/cert.csr', '-CA', f'{self.INSTALL_NEW_PATH[-1]}/ca.pem', '-CAkey', f'{self.INSTALL_NEW_PATH[-1]}/ca-key.pem', '-CAcreateserial', '-out', f'{self.INSTALL_NEW_PATH[-1]}/fullchain.crt', '-days', '1000', '-extensions', 'req_ext', '-extfile', f'{self.INSTALL_NEW_PATH[-1]}/tls.cnf']
        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('Генерация корневого сертификата без ошибок.')
            self.msgbox(f'Сертификат и Ключ сгенерированы, добавьте в доверенные на клиентах файл ca.pem')

    def get_requests(self, prefix_env: str = "CS", dialog: list = None, external:bool = False, **kwarg):
        dialogs = dialog if isinstance(dialog, list) else [
            {
                "env": f'INSTALL_NEW_PATH',
                "enable": None,
                'msg': (
                    f'Р7-Корпоративный сервер:\n\nУкажите путь, где расположить сертификат',
                    f'Путь до директории до каталога хранения обязателен',
                    f'Указанный путь не найден'
                ),
                "func_parse": self.parse_path_dir(),
                "func_check": self.check_extended_dir(),
                "func_visibility": self.visibility_detalization(),
                "detalization": 1
            },
            {
                "env": f'CS_FRONTEND_DOMAIN',
                "enable": True,
                "msg": (
                    f'Введите имя домена',
                    f'Имя домена обязательно к заполнению.',
                    None
                ),
                "func_check": self.check_domain(),
                "func_parse": self.parse_default(),
            },            
            {
                "env": f'CS_CERT_ORG',
                "enable": True,
                "msg": (
                    f'Введите название компании',
                    f'Имя домена обязательно к заполнению.',
                    None
                ),
                "func_check": self.check_name(),
                "func_parse": self.parse_default(),
            },            
            {
                "env": f'CS_CERT_ORG_UNIT',
                "enable": True,
                "msg": (
                    f'Введите название подразделения (филиала)',
                    f'Имя домена обязательно к заполнению.',
                    None
                ),
                "func_check": self.check_name(),
                "func_parse": self.parse_default(),
            },            
        ];
        self.get_dialogs(dialogs)
    
