from flask import Flask, Response, request, jsonify
from pymongo import MongoClient
from bson import ObjectId

import bcrypt
import jwt
from flask_cors import CORS 
import re





app = Flask(__name__)
CORS(app)
client = MongoClient("mongodb://localhost:27017/")
db = client['publication']

if 'publication' not in client.list_database_names():
    db = client['publication']

user_collection = db['user']

if 'user' not in db.list_collection_names():
    db.create_collection('user')

counter_collection = db['counter']

if 'counter' not in db.list_collection_names():
    db.create_collection('counter')
    counter_collection.insert_one({'_id': 'userid', 'seq': 0})


@app.route("/")
def hello_world():
    res = user_collection.find()
    return jsonify(list(res)),200

@app.route("/signup", methods=["POST"])
def register_user():
    data = request.json
    username = data.get("username")
    email = data.get("email")
    password = data.get("password")
    
    if not (username and email and password):
        return jsonify({"message": "Missing required fields"}), 400
    
    user_exists = user_collection.find_one({"email": email})
    if user_exists:
        return jsonify({"message": "Cet utilisateur existe déjà"}), 400
    
    hashed_password = bcrypt.hashpw(password.encode("utf-8"), bcrypt.gensalt(9))
    
    # Increment the counter and retrieve the new value
    counter_doc = counter_collection.find_one_and_update({'_id': 'userid'}, {'$inc': {'seq': 1}}, return_document=True)
    user_id = counter_doc['seq']
    
    new_user = {
        "_id": user_id,
        "username": username,
        "email": email,
        "password": hashed_password.decode("utf-8")
    }

    user_collection.insert_one(new_user)
    
    return jsonify(new_user), 201



@app.route("/login", methods=["POST"])
def login():
    data = request.json
    email = data.get("email")
    password = data.get("password")
    
    if not (email and password):
        return jsonify({"message": "Email and password are required"}), 400
    
    utilisateur = user_collection.find_one({"email": email})
    
    if not utilisateur:
        return jsonify({"message": "Utilisateur introuvable"}), 404
    
    # Password comparison
    if bcrypt.checkpw(password.encode("utf-8"), utilisateur["password"].encode("utf-8")):
        # JWT token generation
        payload = {"email": email, "nom": utilisateur.get("nom")}
        token = jwt.encode(payload, "1234567890", algorithm="HS256")
        return jsonify({"token": token, "message": f"Welcome {utilisateur.get('username')}"})
    else:
        return jsonify({"message": "Mot de passe incorrect"}), 401



# ! craete collection Annonces

if 'Annonces' not in db.list_collection_names():
    db.create_collection('Annonces')

Annonce_collection = db['Annonces']  

@app.route("/add", methods=["POST"])
def add_annonce():
    data = request.json
    Annonce_collection.insert_one(data)
    return jsonify(list(data)), 201


@app.route("/search/<word>", methods=["GET"])
def search_annonce(word):
    regex = re.compile(re.escape(word), re.IGNORECASE)
    annonces = Annonce_collection.find({"titre": {"$regex": regex}})
    results = []
    for annonce in annonces:
        annonce['_id'] = str(annonce['_id'])
        results.append(annonce)
    
    if not results:
        return jsonify({"message": f"No announcements found containing the word '{word}'"}), 404
    return jsonify(results), 200


@app.route("/annonce/delete/<annonce_id>", methods=["DELETE"])
def delete_annonce(annonce_id):
    if not ObjectId.is_valid(annonce_id):
        return jsonify({"message": "Invalid ID format"}), 400

    result = Annonce_collection.delete_one({"_id": ObjectId(annonce_id)})
    if result.deleted_count == 0:
        return jsonify({"message": "Announcement not found"}), 404

    return jsonify({"message": "Announcement deleted successfully"}), 200

# Update  by ID
@app.route("/annonce/update/<annonce_id>", methods=["PUT"])
def update_annonce(annonce_id):
    if not ObjectId.is_valid(annonce_id):
        return jsonify({"message": "Invalid ID format"}), 400

    data = request.json

    result = Annonce_collection.update_one({"_id": ObjectId(annonce_id)}, {"$set": data})
    
    if result.matched_count == 0:
        return jsonify({"message": "Announcement not found"}), 404

    return jsonify({"message": "Announcement updated successfully"}), 200

@app.route("/annonce")
def get_annonces():
    res = Annonce_collection.find()
    annonces = []
    for annonce in res:
        annonce['_id'] = str(annonce['_id'])
        annonces.append(annonce)
    return jsonify(annonces), 200


if __name__ == "__main__":
    app.run(debug=True)