from flask import Flask, request, jsonify, g
from flask_limiter import Limiter
from flask_limiter.util import get_remote_address
import sqlite3
import os
import logging
import sys
import bleach
from datetime import datetime
import re
import hashlib
import time

app = Flask(__name__)
DATABASE = '/var/www/comments/comments.db'

# Set up logging
logging.basicConfig(
    level=logging.DEBUG,
    format='%(asctime)s %(levelname)s: %(message)s',
    handlers=[
        logging.StreamHandler(sys.stderr),
        logging.FileHandler('/var/log/comments.log', mode='a')
    ]
)

# Initialize rate limiter
limiter = Limiter(
    app=app,
    key_func=get_remote_address,
    default_limits=["5 per minute", "100 per day"],
    storage_uri="memory://"
)

def get_db():
    db = getattr(g, '_database', None)
    if db is None:
        db = g._database = sqlite3.connect(DATABASE)
        db.row_factory = sqlite3.Row
    return db

@app.teardown_appcontext
def close_connection(exception):
    db = getattr(g, '_database', None)
    if db is not None:
        db.close()

def is_spam(text):
    spam_patterns = [
        r'https?://\S+',  # URLs
        r'\b(?:viagra|cialis)\b',  # Common spam words
        r'\b(?:buy|sell|cheap)\b.*\b(?:now|online)\b'
    ]
    return any(re.search(pattern, text.lower()) for pattern in spam_patterns)

def validate_input(data):
    if not all(k in data for k in ['name', 'comment', 'post_id']):
        return False
    if len(data['name']) > 50 or len(data['comment']) > 1000:
        return False
    if not data['name'].strip() or not data['comment'].strip():
        return False
    return True

@app.route('/api/comments/<post_id>', methods=['GET'])
@limiter.limit("30 per minute")  # Rate limit for reading comments
def get_comments(post_id):
    try:
        app.logger.debug(f"Getting comments for post_id: {post_id}")
        db = get_db()
        cursor = db.execute(
            'SELECT * FROM comments WHERE post_id = ? ORDER BY created_at DESC',
            [post_id]
        )
        comments = [dict(row) for row in cursor.fetchall()]
        app.logger.debug(f"Found {len(comments)} comments")
        return jsonify(comments)
    except Exception as e:
        app.logger.error(f"Error getting comments: {str(e)}")
        return jsonify({'error': 'Internal server error'}), 500

@app.route('/api/comments', methods=['POST'])
@limiter.limit("5 per minute")  # Stricter rate limit for posting
def add_comment():
    try:
        app.logger.debug("Received comment submission")
        data = request.get_json()
        
        if not data:
            app.logger.warning("No JSON data received")
            return jsonify({'error': 'No data provided'}), 400

        if not validate_input(data):
            app.logger.warning("Invalid input data")
            return jsonify({'error': 'Invalid input'}), 400

        if is_spam(data['comment']):
            app.logger.warning("Spam detected")
            return jsonify({'error': 'Comment detected as potential spam'}), 400

        # Clean input
        clean_name = bleach.clean(data['name'])[:50]
        clean_comment = bleach.clean(data['comment'])[:1000]
        clean_post_id = bleach.clean(data['post_id'])

        # Create hash for duplicate detection
        comment_hash = hashlib.md5(
            f"{clean_name}{clean_comment}".encode()
        ).hexdigest()

        db = get_db()
        
        # Check for duplicate comments
        cursor = db.execute('SELECT id FROM comments WHERE comment_hash = ?', [comment_hash])
        if cursor.fetchone():
            return jsonify({'error': 'Duplicate comment'}), 400

        cursor = db.execute(
            '''INSERT INTO comments 
               (post_id, name, comment, created_at, comment_hash) 
               VALUES (?, ?, ?, ?, ?)''',
            [clean_post_id, clean_name, clean_comment, 
             datetime.utcnow().isoformat(), comment_hash]
        )
        db.commit()
        
        app.logger.debug(f"Comment added successfully with id {cursor.lastrowid}")
        return jsonify({'status': 'success', 'id': cursor.lastrowid}), 201
        
    except Exception as e:
        app.logger.error(f"Error adding comment: {str(e)}")
        return jsonify({'error': 'Internal server error'}), 500

@app.route('/api/comments/<int:comment_id>', methods=['DELETE'])
def delete_comment(comment_id):
    try:
        db = get_db()
        cursor = db.execute('DELETE FROM comments WHERE id = ?', [comment_id])
        db.commit()
        if cursor.rowcount == 0:
            return jsonify({'error': 'Comment not found'}), 404
        return jsonify({'status': 'success', 'message': f'Comment {comment_id} deleted'}), 200
    except Exception as e:
        app.logger.error(f"Error deleting comment: {str(e)}")
        return jsonify({'error': 'Internal server error'}), 500

if __name__ == '__main__':
    app.logger.info("Starting Flask application...")
    app.run(host='127.0.0.1', port=5000)
