from flask import Flask, render_template, request, redirect, url_for, flash, session
import mysql.connector
from mysql.connector import Error
import os
import logging
from contextlib import contextmanager
from dotenv import load_dotenv
from functools import wraps

# Carrega variáveis de ambiente do arquivo .env
load_dotenv()

app = Flask(__name__)
app.secret_key = os.environ.get('SECRET_KEY', 'dev-key-change-in-production')

# Configuração de logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

# Configuração da conexão com o banco de dados usando variáveis de ambiente
DB_CONFIG = {
    'host': os.environ.get('DB_HOST', 'localhost'),
    'user': os.environ.get('DB_USER', 'root'),
    'password': os.environ.get('DB_PASSWORD', ''),
    'database': os.environ.get('DB_NAME', 'seu_banco'),
    'port': int(os.environ.get('DB_PORT', '3306'))
}

# Configuração do banco de login
LOGIN_DB_CONFIG = {
    'host': os.environ.get('DB_HOST', 'localhost'),
    'user': os.environ.get('DB_USER', 'root'),
    'password': os.environ.get('DB_PASSWORD', ''),
    'database': 'login',
    'port': int(os.environ.get('DB_PORT', '3306'))
}

@contextmanager
def get_db_connection(is_login=False, database_name=None):
    """Context manager para gerenciar conexões com o banco de dados
    
    Args:
        is_login: Se True, usa o banco 'login'
        database_name: Nome customizado do banco de dados
    """
    conn = None
    try:
        if is_login:
            config = LOGIN_DB_CONFIG.copy()
        else:
            config = DB_CONFIG.copy()
            # Se for fornecido um nome de banco customizado, usa ele
            if database_name:
                config['database'] = database_name
        
        conn = mysql.connector.connect(**config)
        yield conn
    except Error as e:
        logger.error(f"Erro ao conectar ao banco de dados: {e}")
        raise
    finally:
        if conn and conn.is_connected():
            conn.close()

def login_required(f):
    """Decorator para proteger rotas que requerem login"""
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if 'usuario_id' not in session:
            flash('Por favor, faça login para acessar esta página.', 'error')
            return redirect(url_for('login_page'))
        return f(*args, **kwargs)
    return decorated_function

@app.route('/login', methods=['GET', 'POST'])
def login_page():
    """Página de login"""
    if request.method == 'POST':
        usuario = request.form.get('usuario', '').strip()
        senha = request.form.get('senha', '').strip()
        
        if not usuario or not senha:
            flash('Por favor, preencha usuário e senha.', 'error')
            return redirect(url_for('login_page'))
        
        try:
            with get_db_connection(is_login=True) as conn:
                cursor = conn.cursor(dictionary=True)
                
                cursor.execute("""
                    SELECT chave, usuario, id_cliente 
                    FROM login 
                    WHERE usuario = %s AND senha = %s
                """, (usuario, senha))
                
                resultado = cursor.fetchone()
                cursor.close()
                
                if resultado:
                    # Login bem-sucedido
                    session['usuario_id'] = resultado['chave']
                    session['usuario_nome'] = resultado['usuario']
                    session['id_cliente'] = resultado['id_cliente']
                    logger.info(f"Login bem-sucedido para usuário: {usuario}")
                    flash(f'Bem-vindo, {resultado["usuario"]}!', 'success')
                    return redirect(url_for('index'))
                else:
                    logger.warning(f"Tentativa de login falha para usuário: {usuario}")
                    flash('Usuário ou senha inválidos.', 'error')
                    
        except Error as e:
            logger.error(f"Erro ao fazer login: {e}")
            flash('Erro ao conectar ao banco de dados. Tente novamente.', 'error')
        
        return redirect(url_for('login_page'))
    
    # GET - Exibe a página de login
    if 'usuario_id' in session:
        return redirect(url_for('index'))
    
    return render_template('login.html')

@app.route('/logout')
def logout():
    """Faz logout do usuário"""
    usuario = session.get('usuario_nome', 'Usuário')
    session.clear()
    logger.info(f"Logout realizado para: {usuario}")
    flash('Logout realizado com sucesso!', 'success')
    return redirect(url_for('login_page'))

@app.route('/senha', methods=['GET', 'POST'])
@login_required
def alterar_senha():
    """Tela para alterar a senha do usuário logado"""
    if request.method == 'POST':
        senha_atual = request.form.get('senha_atual', '').strip()
        nova_senha = request.form.get('nova_senha', '').strip()
        confirmar_senha = request.form.get('confirmar_senha', '').strip()

        if not senha_atual or not nova_senha or not confirmar_senha:
            flash('Preencha todos os campos.', 'error')
            return redirect(url_for('alterar_senha'))

        if len(nova_senha) < 4:
            flash('A nova senha deve ter pelo menos 4 caracteres.', 'error')
            return redirect(url_for('alterar_senha'))

        if nova_senha != confirmar_senha:
            flash('A confirmação de senha não confere.', 'error')
            return redirect(url_for('alterar_senha'))

        try:
            with get_db_connection(is_login=True) as conn:
                cursor = conn.cursor()
                usuario_id = session.get('usuario_id')

                # Verifica senha atual
                cursor.execute(
                    "SELECT 1 FROM login WHERE chave = %s AND senha = %s",
                    (usuario_id, senha_atual)
                )
                ok = cursor.fetchone()
                if not ok:
                    flash('Senha atual incorreta.', 'error')
                    cursor.close()
                    return redirect(url_for('alterar_senha'))

                # Atualiza senha
                cursor.execute(
                    "UPDATE login SET senha = %s WHERE chave = %s",
                    (nova_senha, usuario_id)
                )
                conn.commit()
                cursor.close()
                logger.info(f"Senha alterada para usuario_id={usuario_id}")
                flash('Senha atualizada com sucesso.', 'success')
                return redirect(url_for('index'))
        except Error as e:
            logger.error(f"Erro ao alterar senha: {e}")
            flash('Erro ao alterar a senha. Tente novamente.', 'error')
            return redirect(url_for('alterar_senha'))

    # GET
    return render_template('senha.html')

@app.route('/usuarios', methods=['GET', 'POST'])
@login_required
def usuarios():
    """Lista e permite inclusão de novos usuários no banco de login"""
    id_cliente_atual = session.get('id_cliente')
    if not id_cliente_atual:
        flash('Não foi possível identificar o banco do cliente.', 'error')
        return redirect(url_for('index'))

    if request.method == 'POST':
        acao = request.form.get('acao', '')

        # Exclusão de usuário
        if acao == 'delete':
            chave_delete = request.form.get('chave')
            if not chave_delete:
                flash('Chave do usuário não informada.', 'error')
                return redirect(url_for('usuarios'))
            # Impede remover o próprio usuário logado
            if str(chave_delete) == str(session.get('usuario_id')):
                flash('Não é possível excluir o usuário logado.', 'error')
                return redirect(url_for('usuarios'))
            try:
                with get_db_connection(is_login=True) as conn:
                    cursor = conn.cursor()
                    cursor.execute(
                        "DELETE FROM login WHERE chave = %s AND id_cliente = %s",
                        (chave_delete, id_cliente_atual)
                    )
                    conn.commit()
                    cursor.close()
                    flash('Usuário removido.', 'success')
            except Error as e:
                logger.error(f"Erro ao excluir usuário: {e}")
                flash('Erro ao excluir usuário. Tente novamente.', 'error')
            return redirect(url_for('usuarios'))

        novo_usuario = request.form.get('usuario', '').strip()
        nova_senha = request.form.get('senha', '').strip()
        # Força vínculo ao mesmo id_cliente do usuário logado
        novo_id_cliente = id_cliente_atual

        # Validações básicas
        if not novo_usuario or not nova_senha:
            flash('Preencha usuário e senha.', 'error')
            return redirect(url_for('usuarios'))
        if len(novo_usuario) < 3:
            flash('O usuário deve ter pelo menos 3 caracteres.', 'error')
            return redirect(url_for('usuarios'))
        if len(nova_senha) < 4:
            flash('A senha deve ter pelo menos 4 caracteres.', 'error')
            return redirect(url_for('usuarios'))

        try:
            with get_db_connection(is_login=True) as conn:
                cursor = conn.cursor(dictionary=True)
                # Verifica duplicidade de usuário
                cursor.execute(
                    "SELECT 1 AS ok FROM login WHERE usuario = %s AND id_cliente = %s",
                    (novo_usuario, novo_id_cliente)
                )
                existe = cursor.fetchone()
                if existe:
                    flash('Usuário já existe. Escolha outro nome.', 'error')
                    cursor.close()
                    return redirect(url_for('usuarios'))

                cursor.execute(
                    "INSERT INTO login (usuario, senha, id_cliente) VALUES (%s, %s, %s)",
                    (novo_usuario, nova_senha, novo_id_cliente)
                )
                conn.commit()
                cursor.close()
                logger.info(f"Usuário criado: {novo_usuario} (id_cliente={novo_id_cliente})")
                flash('Usuário criado com sucesso.', 'success')
                return redirect(url_for('usuarios'))
        except Error as e:
            logger.error(f"Erro ao incluir usuário: {e}")
            flash('Erro ao incluir usuário. Tente novamente.', 'error')
            return redirect(url_for('usuarios'))

    # GET - lista usuários existentes
    try:
        with get_db_connection(is_login=True) as conn:
            cursor = conn.cursor(dictionary=True)
            cursor.execute(
                "SELECT chave, usuario, id_cliente FROM login WHERE id_cliente = %s ORDER BY chave DESC",
                (id_cliente_atual,)
            )
            lista = cursor.fetchall()
            cursor.close()
    except Error as e:
        logger.error(f"Erro ao listar usuários: {e}")
        flash('Erro ao listar usuários.', 'error')
        lista = []

    return render_template('usuarios.html', usuarios=lista, id_cliente=id_cliente_atual)

@app.route('/')
@login_required
def index():
    """Página inicial que exibe os dados mais recentes"""
    nm, end, t1, t2 = "", "", "", ""
    
    try:
        # Pega o banco de dados do cliente logado
        database = session.get('id_cliente')
        with get_db_connection(database_name=database) as conn:
            cursor = conn.cursor(dictionary=True)
            
            # Query otimizada: busca apenas o último registro
            cursor.execute("""
                SELECT nome, Endereco, tel1, tel2 
                FROM dados_online 
                ORDER BY keychave DESC 
                LIMIT 1
            """)
            
            resultado = cursor.fetchone()
            
            if resultado:
                nm = resultado.get('nome', '')
                end = resultado.get('Endereco', '')
                t1 = resultado.get('tel1', '')
                t2 = resultado.get('tel2', '')
            
            cursor.close()
            
    except Error as e:
        logger.error(f"Erro ao buscar dados: {e}")
        flash('Erro ao carregar os dados. Tente novamente mais tarde.', 'error')
    
    return render_template('index.html', nome=nm, endereco=end, tel1=t1, tel2=t2)

@app.route('/mesas', methods=['GET', 'POST'])
@login_required
def mesas():
    """Rota para movimento de mesas"""
    try:
        logger.info("Acessando movimento de mesas")
        
        # Pega a mesa selecionada (se houver)
        mesa_selecionada = request.form.get('classificacao', '')
        
        # Pega o banco de dados do cliente logado
        database = session.get('id_cliente')
        with get_db_connection(database_name=database) as conn:
            cursor = conn.cursor(dictionary=True)
            
            # Busca todas as mesas distintas
            cursor.execute("""
                SELECT DISTINCT mesanro, status, taxaservico 
                FROM mesa_online 
                ORDER BY mesanro
            """)
            mesas = cursor.fetchall()
            
            # Se uma mesa foi selecionada, busca seus itens
            itens_mesa = []
            subtotal = 0
            taxa_servico = 0
            total = 0
            
            if mesa_selecionada:
                cursor.execute("""
                    SELECT lancamento, codpro, nomedprod, quantidade, valor, taxaservico
                    FROM mesa_online 
                    WHERE mesanro = %s 
                    ORDER BY lancamento
                """, (mesa_selecionada,))
                
                itens = cursor.fetchall()
                
                for item in itens:
                    quant = item['quantidade']
                    valor = item['valor']
                    
                    # Calcula o preço do item
                    if quant >= 1:
                        preco_item = valor * quant
                    else:
                        preco_item = valor
                    
                    # Formata a quantidade
                    if quant == 0.5:
                        quant_formatada = '1/2'
                    elif quant == 0.333:
                        quant_formatada = '1/3'
                    elif quant == 0.25:
                        quant_formatada = '1/4'
                    else:
                        quant_formatada = str(quant)
                    
                    itens_mesa.append({
                        'lancamento': item['lancamento'],
                        'codigo': item['codpro'],
                        'descricao': item['nomedprod'],
                        'quantidade': quant_formatada,
                        'valor': f"{preco_item:.2f}"
                    })
                    
                    subtotal += preco_item
                    taxa_servico = item['taxaservico']
                
                # Calcula taxa de serviço e total
                if taxa_servico:
                    valor_taxa = subtotal * (taxa_servico / 100)
                    total = subtotal + valor_taxa
                else:
                    valor_taxa = 0
                    total = subtotal
            
            # Calcula totais gerais de todas as mesas
            cursor.execute("""
                SELECT quantidade, valor, taxaservico
                FROM mesa_online
            """)
            
            todas_mesas = cursor.fetchall()
            total_geral = 0
            taxa_geral = 0
            
            for item in todas_mesas:
                quant = item['quantidade']
                valor = item['valor']
                
                if quant >= 1:
                    preco = valor * quant
                else:
                    preco = valor
                
                total_geral += preco
                if item['taxaservico']:
                    taxa_percentual = item['taxaservico']
            
            # Calcula taxa e total geral
            if todas_mesas and taxa_percentual:
                taxa_geral = total_geral * (taxa_percentual / 100)
                total_com_taxa = total_geral + taxa_geral
            else:
                taxa_geral = 0
                total_com_taxa = total_geral
            
            cursor.close()
        
        logger.warning(f"Quantidade de mesas carregadas: {len(mesas)}")
        print(f"DEBUG_QUANTIDADE_MESAS: {len(mesas)}")
        return render_template('mesas.html', 
                     mesas=mesas,
                     mesa_selecionada=mesa_selecionada,
                     itens_mesa=itens_mesa,
                     subtotal=f"{subtotal:.2f}" if mesa_selecionada else "0.00",
                     taxa_servico=f"{valor_taxa:.2f}" if mesa_selecionada else "0.00",
                     total=f"{total:.2f}" if mesa_selecionada else "0.00",
                     total_geral=f"{total_geral:.2f}",
                     taxa_geral=f"{taxa_geral:.2f}",
                     total_com_taxa=f"{total_com_taxa:.2f}",
                     tem_mesas=len(todas_mesas) > 0)
        
    except Exception as e:
        logger.error(f"Erro na rota /mesas: {e}")
        flash('Erro ao processar requisição de mesas.', 'error')
        return redirect(url_for('index'))

@app.route('/diario', methods=['GET', 'POST'])
@login_required
def diario():
    """Rota para relatório diário e mensal"""
    try:
        logger.info("Acessando relatório diário")
        
        # Pega o banco de dados do cliente logado
        database = session.get('id_cliente')
        with get_db_connection(database_name=database) as conn:
            cursor = conn.cursor(dictionary=True)
            
            # Busca dados do relatório diário
            cursor.execute("""
                SELECT NomeGrupo, QtGrupo, ValorGrupo 
                FROM vendadiaria 
                ORDER BY chave
            """)
            relatorio_diario = cursor.fetchall()
            
            # Calcula total diário
            total_diario = sum(item['ValorGrupo'] for item in relatorio_diario)
            
            # Busca dados do relatório mensal
            cursor.execute("""
                SELECT lancamento, quantidade, valor 
                FROM vendamensal 
                ORDER BY KeyChave
            """)
            relatorio_mensal = cursor.fetchall()
            
            # Calcula total mensal
            total_mensal = sum(item['valor'] for item in relatorio_mensal)
            
            cursor.close()
        
        return render_template('diario.html',
                             relatorio_diario=relatorio_diario,
                             total_diario=f"{total_diario:.2f}",
                             relatorio_mensal=relatorio_mensal,
                             total_mensal=f"{total_mensal:.2f}")
        
    except Exception as e:
        logger.error(f"Erro na rota /diario: {e}")
        flash('Erro ao processar requisição de relatório diário.', 'error')
        return redirect(url_for('index'))

@app.errorhandler(404)
def page_not_found(e):
    """Tratamento de erro 404"""
    return render_template('404.html'), 404

@app.errorhandler(500)
def internal_error(e):
    """Tratamento de erro 500"""
    logger.error(f"Erro interno do servidor: {e}")
    return render_template('500.html'), 500

if __name__ == '__main__':
    host = os.environ.get('FLASK_RUN_HOST', '0.0.0.0')
    port = int(os.environ.get('FLASK_RUN_PORT', os.environ.get('PORT', '1472')))
    debug = os.environ.get('FLASK_DEBUG', '1') == '1'
    app.run(host=host, port=port, debug=debug)
