from datetime import datetime
import logging
from src.entities.log import Log
import src.database.connection as database
from src.database import queries
from src.database.utils import DatabaseConfig
import src.database.utils as utils
from src.entities.product import Product
import src.api.okvendas as api_okvendas

logger = logging.getLogger()


def job_update_products_semaphore(job_config_dict: dict):
    try:
        db_config = utils.get_database_config(job_config_dict)
        if db_config.sql is None:
            logger.warning(job_config_dict.get('job_name') + ' | Comando sql para criar produtos nao encontrado')
            return

        db = database.Connection(db_config)
        connection = db.get_conect()
        cursor = connection.cursor()

        cursor.execute(db_config.sql)
        cursor.close()

        logger.info(job_config_dict.get('job_name') + f' | Produtos marcados para atualizar no banco semaforo: {cursor.rowcount}')
        connection.commit()
        connection.close()

    except Exception as e:
        logger.error(job_config_dict.get('job_name') + f' | Erro ao atualizar produtos no banco semaforo: {e}', exc_info=True)


def job_insert_products_semaphore(job_config_dict: dict):
    """
    Job que realiza a insercao dos produtos no banco semaforo
    Args:
        job_config_dict: Dicionario contendo configuracoes do job (obtidos na api oking)
    """
    try:
        db_config = utils.get_database_config(job_config_dict)
        if db_config.sql is None:
            logger.warning(job_config_dict.get('job_name') + ' | Comando sql para criar produtos nao encontrado')
            return

        # abre a connection com o banco
        db = database.Connection(db_config)
        connection = db.get_conect()
        cursor = connection.cursor()

        try:
            sql: str = db_config.sql
            if db_config.sql[len(db_config.sql) - 1] is ';':
                sql = db_config.sql[len(db_config.sql) - 1] = ' '

            logger.info(job_config_dict.get('job_name') + f' | Inserindo produtos no banco semáforo ')
            cursor.execute(sql)
            connection.commit()
            logger.info(job_config_dict.get('job_name') + f' | {cursor.rowcount} produtos inseridos no banco semáforo')
        except Exception as e:
            logger.error(job_config_dict.get('job_name') + f' | Erro ao inserir produtos no banco semaforo: {e}')
            api_okvendas.post_log(Log(job_config_dict.get('job_name') + ' | Erro ao inserir produtos no banco semaforo: ' + str(e), datetime.now().isoformat(), '', 'PRODUTO'))
            cursor.close()
            connection.close()

        cursor.close()
        connection.close()
    except Exception as e:
        logger.error(job_config_dict.get('job_name') + f' | Erro ao durante a execucao do job: {e}')
        api_okvendas.post_log(Log(job_config_dict.get('job_name') + ' | Erro ao durante a execucao do job: ' + str(e), datetime.now().isoformat(), '', 'PRODUTO'))


def job_send_products(job_config_dict: dict):
    """
    Job que realiza a leitura dos produtos contidos no banco semaforo e envia para a api okvendas
    Args:
        job_config_dict: Dicionario contendo configuracoes do job (obtidos na api oking)
    """
    try:
        db_config = utils.get_database_config(job_config_dict)
        if db_config.sql is None:
            logger.warning(job_config_dict.get('job_name') + ' | Comando sql para criar produtos nao encontrado')
            return

        produtos = query_products(db_config)
        if len(produtos) <= 0:
            logger.warning(job_config_dict.get('job_name') + ' | Nao existem produtos para criar no momento')
            return

        produtos_protocolar = []
        for prod in produtos:
            try:
                response = api_okvendas.post_produtos([prod])

                for res in response:
                    if res.status > 1:
                        logger.warning(job_config_dict.get('job_name') + f' | Erro ao gerar produto {res.codigo_erp} na api okvendas. Erro gerado na api: {res.message}')
                    else:
                        logger.info(job_config_dict.get('job_name') + f' | Produto {res.codigo_erp} criado com sucesso')
                        produtos_protocolar.append({'codigo_erp': prod.codigo_erp, 'codigo_erp_sku': prod.preco_estoque[0].codigo_erp_atributo})
            except Exception as e:
                logger.error(job_config_dict.get('job_name') + f' | Erro durante o envio de produtos: {e}', exc_info=True)

        protocol_products(produtos_protocolar, db_config)

    except Exception as e:
        logger.error(job_config_dict.get('job_name') + f' | Erro ao durante a execucao do job: {e}', exc_info=True)


def query_products(db_config: DatabaseConfig):
    """
    Consulta os produtos contidos no banco semaforo juntamente com os dados do banco do ERP
    Args:
        db_config: Configuracao do banco de dados

    Returns:
        Lista de produtos
    """
    # abre a connection com o banco
    db = database.Connection(db_config)
    connection = db.get_conect()
    # connection.start_transaction()
    cursor = connection.cursor()

    # obtem os dados do banco
    # logger.warning(query)
    cursor.execute(db_config.sql)
    columns = [col[0] for col in cursor.description]
    results = [dict(zip(columns, row)) for row in cursor.fetchall()]

    cursor.close()
    connection.close()

    produtos = []
    for result in results:
        produtos.append(Product(result))

    return produtos


def protocol_products(products: list, db_config: DatabaseConfig) -> None:
    """
    Protocola no banco semaforo os produtos que foram enviados para a api okvendas
    Args:
        products: Lista de produtos enviados para a api okvendas
        db_config: Configuracao do banco de dados
    """
    try:
        if len(products) > 0:
            db = database.Connection(db_config)
            connection = db.get_conect()
            cursor = connection.cursor()
            for prod in products:
                try:
                    dados_produto = [prod['codigo_erp'], prod['codigo_erp_sku']]
                    logger.info(f'Protocolando codigo_erp {dados_produto[0]} sku {dados_produto[1]}')
                    cursor.execute(queries.get_product_protocol_command(db_config.db_type), queries.get_command_parameter(db_config.db_type, dados_produto))
                    logger.info(f'Linhas afetadas {cursor.rowcount}')
                except Exception as e:
                    logger.error(f'Erro ao protocolar sku {prod["codigo_erp_sku"]}: {e}', exc_info=True)
            cursor.close()
            connection.commit()
            connection.close()
    except Exception as e:
        raise e
