from flask import Flask, request, jsonify, send_file
from flask_cors import CORS
from flask_socketio import SocketIO, emit, join_room, leave_room
from flask_jwt_extended import JWTManager, create_access_token, jwt_required, get_jwt_identity
from config import Config
from models import db, User, DetectionEvent, MonitoringSession
from detection_service import DetectionService
from reportlab.lib.pagesizes import letter
from reportlab.platypus import SimpleDocTemplate, Table, TableStyle, Paragraph, Spacer
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib import colors
from reportlab.lib.units import inch
import os
import time
import uuid
from datetime import datetime

app = Flask(__name__)
app.config.from_object(Config)

CORS(app, resources={r"/*": {"origins": "*"}})
jwt = JWTManager(app)
socketio = SocketIO(app, cors_allowed_origins="*", async_mode='eventlet')

db.init_app(app)

# Armazenar serviços de detecção ativos
active_services = {}

def init_db():
    with app.app_context():
        db.create_all()
        # Criar usuário padrão se não existir
        if not User.query.filter_by(username=Config.DEFAULT_USERNAME).first():
            default_user = User(username=Config.DEFAULT_USERNAME)
            default_user.set_password(Config.DEFAULT_PASSWORD)
            db.session.add(default_user)
            db.session.commit()

# ==================== AUTENTICAÇÃO ====================

@app.route('/api/auth/login', methods=['POST'])
def login():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')
    
    user = User.query.filter_by(username=username).first()
    
    if user and user.check_password(password):
        access_token = create_access_token(identity=user.id)
        return jsonify({
            'access_token': access_token,
            'user_id': user.id,
            'username': user.username
        }), 200
    
    return jsonify({'message': 'Credenciais inválidas'}), 401

@app.route('/api/auth/register', methods=['POST'])
@jwt_required()
def register():
    data = request.get_json()
    username = data.get('username')
    password = data.get('password')
    
    if User.query.filter_by(username=username).first():
        return jsonify({'message': 'Usuário já existe'}), 400
    
    user = User(username=username)
    user.set_password(password)
    db.session.add(user)
    db.session.commit()
    
    return jsonify({'message': 'Usuário criado com sucesso'}), 201

# ==================== SESSÕES DE MONITORAMENTO ====================

@app.route('/api/sessions', methods=['POST'])
@jwt_required()
def create_session():
    user_id = get_jwt_identity()
    data = request.get_json()
    target_url = data.get('target_url', Config.TARGET_URL)
    
    session_id = str(uuid.uuid4())
    session = MonitoringSession(
        session_id=session_id,
        user_id=user_id,
        target_url=target_url,
        status='active'
    )
    db.session.add(session)
    db.session.commit()
    
    # Criar serviço de detecção
    service = DetectionService(socketio, db, session_id)
    active_services[session_id] = service
    
    return jsonify({
        'session_id': session_id,
        'session': session.to_dict()
    }), 201

@app.route('/api/sessions/<session_id>/start', methods=['POST'])
@jwt_required()
def start_session(session_id):
    data = request.get_json()
    target_url = data.get('target_url')
    
    if session_id not in active_services:
        return jsonify({'message': 'Sessão não encontrada'}), 404
    
    try:
        service = active_services[session_id]
        success = service.start_monitoring(target_url)
        
        if success:
            return jsonify({'message': 'Monitoramento iniciado com sucesso'}), 200
        else:
            return jsonify({'message': 'Falha ao iniciar monitoramento'}), 500
    except Exception as e:
        error_msg = str(e)
        print(f"Erro ao iniciar monitoramento: {error_msg}")
        return jsonify({'message': error_msg}), 500

@app.route('/api/sessions/<session_id>/stop', methods=['POST'])
@jwt_required()
def stop_session(session_id):
    if session_id not in active_services:
        return jsonify({'message': 'Sessão não encontrada'}), 404
    
    service = active_services[session_id]
    service.stop_monitoring()
    
    session = MonitoringSession.query.filter_by(session_id=session_id).first()
    if session:
        session.end_time = datetime.utcnow()
        session.status = 'stopped'
        session.total_detections = service.detected_count
        db.session.commit()
    
    return jsonify({'message': 'Monitoramento encerrado'}), 200

@app.route('/api/sessions/<session_id>', methods=['GET'])
@jwt_required()
def get_session(session_id):
    session = MonitoringSession.query.filter_by(session_id=session_id).first()
    if not session:
        return jsonify({'message': 'Sessão não encontrada'}), 404
    
    return jsonify(session.to_dict()), 200

@app.route('/api/sessions', methods=['GET'])
@jwt_required()
def get_sessions():
    user_id = get_jwt_identity()
    sessions = MonitoringSession.query.filter_by(user_id=user_id).order_by(MonitoringSession.start_time.desc()).all()
    return jsonify([s.to_dict() for s in sessions]), 200

# ==================== DETECÇÕES ====================

@app.route('/api/sessions/<session_id>/detections', methods=['GET'])
@jwt_required()
def get_detections(session_id):
    detections = DetectionEvent.query.filter_by(session_id=session_id).order_by(DetectionEvent.timestamp.desc()).all()
    return jsonify([d.to_dict() for d in detections]), 200

# ==================== RELATÓRIOS ====================

@app.route('/api/sessions/<session_id>/report', methods=['GET'])
@jwt_required()
def generate_report(session_id):
    session = MonitoringSession.query.filter_by(session_id=session_id).first()
    if not session:
        return jsonify({'message': 'Sessão não encontrada'}), 404
    
    detections = DetectionEvent.query.filter_by(session_id=session_id).order_by(DetectionEvent.timestamp.asc()).all()
    
    # Gerar PDF
    f_date = time.strftime('%Y-%m-%d', time.localtime(session.start_time.timestamp()))
    f_start = time.strftime('%H-%M-%S', time.localtime(session.start_time.timestamp()))
    f_end = time.strftime('%H-%M-%S', time.localtime(session.end_time.timestamp() if session.end_time else time.time()))
    filename = f"Relatório_{f_date}_{f_start}_{f_end}.pdf"
    
    try:
        doc = SimpleDocTemplate(filename, pagesize=letter, topMargin=1.5 * inch)
        styles = getSampleStyleSheet()
        elements = []
        
        title_style = styles['Title']
        title_style.fontName = 'Helvetica-Bold'
        title_style.fontSize = 16
        title_style.spaceAfter = 20
        
        elements.append(Paragraph("Relatório de Eventos de Detecção de Pessoas", title_style))
        
        normal_style = styles['Normal']
        normal_style.fontSize = 10
        normal_style.leading = 14
        
        elements.append(Paragraph(f"<b>Data de Geração:</b> {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}", normal_style))
        elements.append(Paragraph(f"<b>Total de Eventos:</b> {len(detections)}", normal_style))
        elements.append(Spacer(1, 15))
        
        elements.append(Paragraph(f"<b>Início:</b> {session.start_time.strftime('%Y-%m-%d %H:%M:%S')}", normal_style))
        if session.end_time:
            elements.append(Paragraph(f"<b>Fim:</b> {session.end_time.strftime('%Y-%m-%d %H:%M:%S')}", normal_style))
            duration = (session.end_time - session.start_time).total_seconds()
            elements.append(Paragraph(f"<b>Duração:</b> {duration:.2f} segundos", normal_style))
        elements.append(Spacer(1, 25))
        
        h2_style = styles['Heading2']
        h2_style.fontSize = 12
        h2_style.spaceAfter = 6
        
        elements.append(Paragraph("Detalhes dos Eventos:", h2_style))
        elements.append(Spacer(1, 5))
        
        table_data = [['ID', 'Track ID', 'Detalhe', 'Horário']]
        for det in detections:
            table_data.append([
                str(det.id),
                str(det.track_id),
                det.detail,
                det.timestamp.strftime('%H:%M:%S')
            ])
        
        t = Table(table_data, colWidths=[40, 60, 200, 120])
        t.setStyle(TableStyle([
            ('BACKGROUND', (0, 0), (-1, 0), colors.white),
            ('TEXTCOLOR', (0, 0), (-1, 0), colors.black),
            ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
            ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
            ('FONTSIZE', (0, 0), (-1, -1), 10),
            ('BOTTOMPADDING', (0, 0), (-1, 0), 8),
            ('LINEBELOW', (0, 0), (-1, 0), 1, colors.black),
            ('GRID', (0, 0), (-1, -1), 0.5, colors.lightgrey),
        ]))
        elements.append(t)
        
        doc.build(elements)
        
        return send_file(filename, as_attachment=True, download_name=filename)
    
    except Exception as e:
        return jsonify({'message': f'Erro ao gerar relatório: {str(e)}'}), 500

# ==================== ARQUIVOS ESTÁTICOS ====================

@app.route('/finland_alarm.mp3')
def serve_alarm():
    return send_file(Config.ALARM_FILE, mimetype='audio/mpeg')

# ==================== WEBSOCKET ====================

@socketio.on('connect')
def handle_connect(auth):
    # Autenticação simplificada - verificar token na query string ou auth
    token = request.args.get('token') or (auth.get('token') if auth else None)
    
    if not token:
        print("WebSocket: Token não fornecido")
        # Permitir conexão sem token para desenvolvimento (remover em produção)
        emit('connected', {'message': 'Conectado ao servidor (sem autenticação)'})
        return True
    
    try:
        from flask_jwt_extended import decode_token
        decoded = decode_token(token)
        user_id = decoded.get('sub')
        print(f"WebSocket: Usuário {user_id} conectado")
        emit('connected', {'message': 'Conectado ao servidor'})
        return True
    except Exception as e:
        print(f"WebSocket: Erro de autenticação - {e}")
        # Em desenvolvimento, permitir conexão mesmo com erro de token
        emit('connected', {'message': 'Conectado (autenticação falhou, mas permitido em dev)'})
        return True

@socketio.on('join_session')
def handle_join_session(data):
    session_id = data.get('session_id')
    if session_id:
        join_room(session_id)
        emit('joined', {'message': f'Entrou na sessão {session_id}'})

@socketio.on('leave_session')
def handle_leave_session(data):
    session_id = data.get('session_id')
    if session_id:
        leave_room(session_id)
        emit('left', {'message': f'Saiu da sessão {session_id}'})

@socketio.on('disconnect')
def handle_disconnect():
    print('Cliente desconectado')

if __name__ == '__main__':
    init_db()
    socketio.run(app, host='0.0.0.0', port=5000, debug=True, allow_unsafe_werkzeug=True)

