from flask import Flask, request, jsonify
from flask_cors import CORS
from pymongo import MongoClient
from datetime import datetime, timedelta
import matplotlib
matplotlib.use('Agg')
import matplotlib.pyplot as plt
import base64
import io
import bcrypt
import os
from bson import ObjectId
import json

app = Flask(__name__)
CORS(app)

# Configurações do MongoDB
MONGO_URI = os.getenv('MONGO_URI', 'mongodb://localhost:27017/')
DB_NAME = 'CtrlCash'

# Conexão com MongoDB
try:
    client = MongoClient(MONGO_URI)
    db = client[DB_NAME]
    print(f"✅ Conectado ao MongoDB: {DB_NAME}")
except Exception as e:
    print(f"❌ Erro ao conectar com MongoDB: {e}")
    exit(1)

# Collections
users_collection = db['users']
transactions_collection = db['transactions']
categories_collection = db['categories']

class JSONEncoder(json.JSONEncoder):
    def default(self, obj):
        if isinstance(obj, ObjectId):
            return str(obj)
        if isinstance(obj, datetime):
            return obj.isoformat()
        return super().default(obj)

app.json_encoder = JSONEncoder

# Categorias padrão
default_categories = [
    {"name": "Alimentação", "type": "expense", "color": "#FF6B6B"},
    {"name": "Transporte", "type": "expense", "color": "#4ECDC4"},
    {"name": "Moradia", "type": "expense", "color": "#45B7D1"},
    {"name": "Saúde", "type": "expense", "color": "#96CEB4"},
    {"name": "Educação", "type": "expense", "color": "#FFEAA7"},
    {"name": "Lazer", "type": "expense", "color": "#DDA0DD"},
    {"name": "Salário", "type": "income", "color": "#98D8C8"},
    {"name": "Investimentos", "type": "income", "color": "#F7DC6F"},
    {"name": "Freelance", "type": "income", "color": "#BB8FCE"},
    {"name": "Outros", "type": "income", "color": "#95a5a6"},
    {"name": "Outros", "type": "expense", "color": "#95a5a6"}
]

# Funções auxiliares
def hash_password(password):
    return bcrypt.hashpw(password.encode('utf-8'), bcrypt.gensalt()).decode('utf-8')

def check_password(password, hashed):
    return bcrypt.checkpw(password.encode('utf-8'), hashed.encode('utf-8'))

def init_default_categories(user_id):
    """Insere categorias padrão para um usuário"""
    categories = []
    for cat in default_categories:
        categories.append({
            **cat,
            "user_id": ObjectId(user_id),
            "created_at": datetime.now()
        })
    if categories:
        categories_collection.insert_many(categories)

# ROTAS DE AUTENTICAÇÃO
@app.route('/api/auth/register', methods=['POST'])
def register():
    try:
        data = request.get_json()
        email = data.get('email', '').strip().lower()
        password = data.get('password', '')
        name = data.get('name', '').strip()
        
        if not email or not password or not name:
            return jsonify({"error": "Todos os campos são obrigatórios"}), 400
        
        if len(password) < 6:
            return jsonify({"error": "A senha deve ter pelo menos 6 caracteres"}), 400
        
        # Verificar se usuário já existe
        if users_collection.find_one({"email": email}):
            return jsonify({"error": "Email já cadastrado"}), 400
        
        # Criar usuário
        user_data = {
            'email': email,
            'password': hash_password(password),
            'name': name,
            'created_at': datetime.now(),
            'profile': {
                'monthly_income_goal': 5000,
                'monthly_expense_limit': 2500,
                'currency': 'BRL'
            }
        }
        
        result = users_collection.insert_one(user_data)
        user_id = result.inserted_id
        
        # Inicializar categorias
        init_default_categories(user_id)
        
        return jsonify({
            "message": "Usuário criado com sucesso",
            "user": {
                "id": str(user_id),
                "email": email,
                "name": name,
                "profile": user_data['profile']
            }
        }), 201
        
    except Exception as e:
        print(f"Erro no registro: {e}")
        return jsonify({"error": "Erro interno do servidor"}), 500

@app.route('/api/auth/login', methods=['POST'])
def login():
    try:
        data = request.get_json()
        email = data.get('email', '').strip().lower()
        password = data.get('password', '')
        
        if not email or not password:
            return jsonify({"error": "Email e senha são obrigatórios"}), 400
        
        user = users_collection.find_one({"email": email})
        
        if not user or not check_password(password, user['password']):
            return jsonify({"error": "Credenciais inválidas"}), 401
        
        return jsonify({
            "message": "Login realizado com sucesso",
            "user": {
                "id": str(user['_id']),
                "email": user['email'],
                "name": user['name'],
                "profile": user.get('profile', {})
            }
        }), 200
        
    except Exception as e:
        print(f"Erro no login: {e}")
        return jsonify({"error": "Erro interno do servidor"}), 500

# ROTAS DE TRANSAÇÕES
@app.route('/api/transactions', methods=['GET'])
def get_transactions():
    try:
        user_id = request.args.get('user_id')
        if not user_id:
            return jsonify({"transactions": []}), 200
        
        transactions = list(transactions_collection.find(
            {"user_id": ObjectId(user_id)}
        ).sort("date", -1))
        
        # Converter ObjectId para string
        for transaction in transactions:
            transaction['id'] = str(transaction['_id'])
            transaction['user_id'] = str(transaction['user_id'])
            del transaction['_id']
        
        return jsonify({"transactions": transactions}), 200
        
    except Exception as e:
        print(f"Erro ao buscar transações: {e}")
        return jsonify({"error": "Erro ao buscar transações"}), 500

@app.route('/api/transactions', methods=['POST'])
def add_transaction():
    try:
        data = request.get_json()
        user_id = data.get('user_id')
        
        if not user_id:
            return jsonify({"error": "User ID é obrigatório"}), 400
        
        # Validar dados
        amount = float(data.get('amount', 0))
        description = data.get('description', '').strip()
        category = data.get('category', 'Outros')
        transaction_type = data.get('type', 'expense')
        date_str = data.get('date', '')
        
        if amount <= 0:
            return jsonify({"error": "Valor deve ser maior que zero"}), 400
        
        if not description:
            return jsonify({"error": "Descrição é obrigatória"}), 400
        
        # Usar data exata do frontend
        if not date_str:
            date_str = datetime.now().strftime('%Y-%m-%d')
        
        new_transaction = {
            "user_id": ObjectId(user_id),
            "amount": amount,
            "description": description,
            "category": category,
            "type": transaction_type,
            "date": date_str,
            "created_at": datetime.now()
        }
        
        result = transactions_collection.insert_one(new_transaction)
        new_transaction['id'] = str(result.inserted_id)
        new_transaction['user_id'] = user_id
        del new_transaction['_id']
        
        return jsonify({
            "message": "Transação adicionada com sucesso",
            "transaction": new_transaction
        }), 201
        
    except Exception as e:
        print(f"Erro ao adicionar transação: {e}")
        return jsonify({"error": "Erro ao adicionar transação"}), 500

@app.route('/api/transactions/<transaction_id>', methods=['DELETE'])
def delete_transaction(transaction_id):
    try:
        user_id = request.args.get('user_id')
        if not user_id:
            return jsonify({"error": "User ID é obrigatório"}), 400
        
        result = transactions_collection.delete_one({
            "_id": ObjectId(transaction_id),
            "user_id": ObjectId(user_id)
        })
        
        if result.deleted_count == 0:
            return jsonify({"error": "Transação não encontrada"}), 404
        
        return jsonify({"message": "Transação deletada com sucesso"}), 200
        
    except Exception as e:
        print(f"Erro ao deletar transação: {e}")
        return jsonify({"error": "Erro ao deletar transação"}), 500

# ROTAS DE CATEGORIAS
@app.route('/api/categories', methods=['GET'])
def get_categories():
    try:
        user_id = request.args.get('user_id')
        
        if user_id:
            # Buscar categorias do usuário
            categories = list(categories_collection.find({"user_id": ObjectId(user_id)}))
            for category in categories:
                category['id'] = str(category['_id'])
                category['user_id'] = str(category['user_id'])
                del category['_id']
        else:
            # Retornar categorias padrão
            categories = [{"id": i, **cat} for i, cat in enumerate(default_categories)]
        
        return jsonify({"categories": categories}), 200
        
    except Exception as e:
        print(f"Erro ao buscar categorias: {e}")
        return jsonify({"categories": default_categories}), 200

@app.route('/api/categories', methods=['POST'])
def add_category():
    try:
        data = request.get_json()
        user_id = data.get('user_id')
        name = data.get('name', '').strip()
        category_type = data.get('type')
        color = data.get('color', '#6c757d')
        
        if not user_id:
            return jsonify({"error": "User ID é obrigatório"}), 400
        
        if not name:
            return jsonify({"error": "Nome da categoria é obrigatório"}), 400
        
        if not category_type or category_type not in ['income', 'expense']:
            return jsonify({"error": "Tipo de categoria inválido"}), 400
        
        # Verificar se categoria já existe
        existing_category = categories_collection.find_one({
            "user_id": ObjectId(user_id),
            "name": name,
            "type": category_type
        })
        
        if existing_category:
            return jsonify({"error": "Categoria já existe"}), 400
        
        new_category = {
            "user_id": ObjectId(user_id),
            "name": name,
            "type": category_type,
            "color": color,
            "created_at": datetime.now()
        }
        
        result = categories_collection.insert_one(new_category)
        new_category['id'] = str(result.inserted_id)
        new_category['user_id'] = user_id
        del new_category['_id']
        
        return jsonify({
            "message": "Categoria adicionada com sucesso",
            "category": new_category
        }), 201
        
    except Exception as e:
        print(f"Erro ao adicionar categoria: {e}")
        return jsonify({"error": "Erro ao adicionar categoria"}), 500

# ROTAS DO DASHBOARD
@app.route('/api/dashboard/summary', methods=['GET'])
def get_dashboard_summary():
    try:
        user_id = request.args.get('user_id')
        if not user_id:
            return jsonify({
                "total_income": 0,
                "total_expenses": 0,
                "balance": 0,
                "recent_transactions": []
            }), 200
        
        # Calcular totais do mês atual
        start_of_month = datetime.now().replace(day=1, hour=0, minute=0, second=0, microsecond=0)
        
        # Pipeline para receitas do mês
        pipeline_income = [
            {"$match": {
                "user_id": ObjectId(user_id),
                "type": "income",
                "date": {"$gte": start_of_month.strftime('%Y-%m-%d')}
            }},
            {"$group": {"_id": None, "total": {"$sum": "$amount"}}}
        ]
        
        # Pipeline para despesas do mês
        pipeline_expenses = [
            {"$match": {
                "user_id": ObjectId(user_id),
                "type": "expense",
                "date": {"$gte": start_of_month.strftime('%Y-%m-%d')}
            }},
            {"$group": {"_id": None, "total": {"$sum": "$amount"}}}
        ]
        
        income_result = list(transactions_collection.aggregate(pipeline_income))
        expense_result = list(transactions_collection.aggregate(pipeline_expenses))
        
        total_income = income_result[0]['total'] if income_result else 0
        total_expenses = expense_result[0]['total'] if expense_result else 0
        balance = total_income - total_expenses
        
        # Últimas 5 transações
        recent_transactions = list(transactions_collection.find(
            {"user_id": ObjectId(user_id)}
        ).sort("date", -1).limit(5))
        
        for transaction in recent_transactions:
            transaction['id'] = str(transaction['_id'])
            transaction['user_id'] = str(transaction['user_id'])
            del transaction['_id']
        
        return jsonify({
            "total_income": round(total_income, 2),
            "total_expenses": round(total_expenses, 2),
            "balance": round(balance, 2),
            "recent_transactions": recent_transactions
        }), 200
        
    except Exception as e:
        print(f"Erro no dashboard: {e}")
        return jsonify({
            "total_income": 0,
            "total_expenses": 0,
            "balance": 0,
            "recent_transactions": []
        }), 200

@app.route('/api/dashboard/chart')
def get_chart():
    try:
        user_id = request.args.get('user_id')
        chart_type = request.args.get('type', 'monthly')
        
        if not user_id:
            return jsonify({"error": "User ID é obrigatório"}), 400
        
        plt.figure(figsize=(10, 6))
        
        if chart_type == 'monthly':
            # Últimos 6 meses
            six_months_ago = datetime.now() - timedelta(days=180)
            
            pipeline = [
                {"$match": {
                    "user_id": ObjectId(user_id),
                    "date": {"$gte": six_months_ago.strftime('%Y-%m-%d')}
                }},
                {"$group": {
                    "_id": {"$substr": ["$date", 0, 7]},  # Extrair YYYY-MM
                    "income": {"$sum": {"$cond": [{"$eq": ["$type", "income"]}, "$amount", 0]}},
                    "expenses": {"$sum": {"$cond": [{"$eq": ["$type", "expense"]}, "$amount", 0]}}
                }},
                {"$sort": {"_id": 1}},
                {"$limit": 6}
            ]
            
            result = list(transactions_collection.aggregate(pipeline))
            
            if result:
                months = [r['_id'] for r in result]
                income = [r['income'] for r in result]
                expenses = [r['expenses'] for r in result]
                
                x = range(len(months))
                width = 0.35
                
                plt.bar([i - width/2 for i in x], income, width, label='Receitas', color='#28a745')
                plt.bar([i + width/2 for i in x], expenses, width, label='Despesas', color='#dc3545')
                plt.xlabel('Mês')
                plt.ylabel('Valor (R$)')
                plt.title('Receitas vs Despesas - Últimos 6 Meses')
                plt.xticks(x, months, rotation=45)
                plt.legend()
                plt.tight_layout()
            else:
                plt.text(0.5, 0.5, 'Sem dados para exibir', 
                        ha='center', va='center', transform=plt.gca().transAxes)
            
        elif chart_type == 'categories':
            # Gastos por categoria (últimos 30 dias)
            thirty_days_ago = datetime.now() - timedelta(days=30)
            
            pipeline = [
                {"$match": {
                    "user_id": ObjectId(user_id),
                    "type": "expense",
                    "date": {"$gte": thirty_days_ago.strftime('%Y-%m-%d')}
                }},
                {"$group": {
                    "_id": "$category",
                    "total": {"$sum": "$amount"}
                }}
            ]
            
            result = list(transactions_collection.aggregate(pipeline))
            
            if result:
                categories = [r['_id'] for r in result]
                amounts = [r['total'] for r in result]
                
                plt.pie(amounts, labels=categories, autopct='%1.1f%%', startangle=90)
                plt.title('Distribuição de Gastos por Categoria (Últimos 30 dias)')
            else:
                plt.text(0.5, 0.5, 'Sem dados de gastos', 
                        ha='center', va='center', transform=plt.gca().transAxes)
        
        # Converter para base64
        buffer = io.BytesIO()
        plt.savefig(buffer, format='png', dpi=100, bbox_inches='tight')
        buffer.seek(0)
        image_base64 = base64.b64encode(buffer.getvalue()).decode()
        plt.close()
        
        return jsonify({
            "chart": f"data:image/png;base64,{image_base64}"
        }), 200
        
    except Exception as e:
        print(f"Erro ao gerar gráfico: {e}")
        return jsonify({"error": "Erro ao gerar gráfico"}), 500

# ROTAS DE PERFIL
@app.route('/api/user/profile', methods=['GET'])
def get_profile():
    try:
        user_id = request.args.get('user_id')
        if not user_id:
            return jsonify({"error": "User ID é obrigatório"}), 400
        
        user = users_collection.find_one({"_id": ObjectId(user_id)})
        if not user:
            return jsonify({"error": "Usuário não encontrado"}), 404
        
        return jsonify({
            "user": {
                "id": str(user['_id']),
                "name": user['name'],
                "email": user['email'],
                "profile": user.get('profile', {})
            }
        }), 200
        
    except Exception as e:
        print(f"Erro ao buscar perfil: {e}")
        return jsonify({"error": "Erro ao buscar perfil"}), 500

@app.route('/api/user/profile', methods=['PUT'])
def update_profile():
    try:
        data = request.get_json()
        user_id = data.get('user_id')
        name = data.get('name', '').strip()
        email = data.get('email', '').strip().lower()
        profile = data.get('profile', {})
        
        if not user_id:
            return jsonify({"error": "User ID é obrigatório"}), 400
        
        if not name:
            return jsonify({"error": "Nome é obrigatório"}), 400
        
        # Verificar se email já existe (para outro usuário)
        existing_user = users_collection.find_one({
            "email": email,
            "_id": {"$ne": ObjectId(user_id)}
        })
        
        if existing_user:
            return jsonify({"error": "Email já está em uso"}), 400
        
        update_data = {
            "name": name,
            "email": email,
            "profile": profile
        }
        
        result = users_collection.update_one(
            {"_id": ObjectId(user_id)},
            {"$set": update_data}
        )
        
        if result.modified_count == 0:
            return jsonify({"error": "Nenhuma alteração realizada"}), 400
        
        return jsonify({
            "message": "Perfil atualizado com sucesso",
            "user": {
                "id": user_id,
                "name": name,
                "email": email,
                "profile": profile
            }
        }), 200
        
    except Exception as e:
        print(f"Erro ao atualizar perfil: {e}")
        return jsonify({"error": "Erro ao atualizar perfil"}), 500

@app.route('/api/user/change-password', methods=['PUT'])
def change_password():
    try:
        data = request.get_json()
        user_id = data.get('user_id')
        current_password = data.get('current_password')
        new_password = data.get('new_password')
        
        if not user_id:
            return jsonify({"error": "User ID é obrigatório"}), 400
        
        user = users_collection.find_one({"_id": ObjectId(user_id)})
        if not user:
            return jsonify({"error": "Usuário não encontrado"}), 404
        
        if not check_password(current_password, user['password']):
            return jsonify({"error": "Senha atual incorreta"}), 400
        
        if len(new_password) < 6:
            return jsonify({"error": "A nova senha deve ter pelo menos 6 caracteres"}), 400
        
        users_collection.update_one(
            {"_id": ObjectId(user_id)},
            {"$set": {"password": hash_password(new_password)}}
        )
        
        return jsonify({"message": "Senha alterada com sucesso"}), 200
        
    except Exception as e:
        print(f"Erro ao alterar senha: {e}")
        return jsonify({"error": "Erro ao alterar senha"}), 500

# Rota health check
@app.route('/api/health', methods=['GET'])
def health_check():
    try:
        # Testar conexão com MongoDB
        client.admin.command('ismaster')
        return jsonify({
            "status": "OK", 
            "message": "Backend e MongoDB funcionando",
            "timestamp": datetime.now().isoformat()
        }), 200
    except Exception as e:
        return jsonify({
            "status": "ERROR",
            "message": f"Erro no MongoDB: {e}"
        }), 500

@app.route('/')
def index():
    return jsonify({
        "message": "CtrlCash API está funcionando!",
        "version": "1.0.0",
        "timestamp": datetime.now().isoformat()
    })

if __name__ == '__main__':
    print("🚀 Iniciando CtrlCash API com MongoDB...")
    print(f"📊 MongoDB: {MONGO_URI}")
    print(f"💾 Database: {DB_NAME}")
    app.run(debug=False, host='0.0.0.0', port=5000)