from flask import Flask, jsonify, request, send_from_directory, abort
import requests
import os
from pymongo import MongoClient, UpdateOne
from dotenv import load_dotenv
from datetime import datetime
from email.message import EmailMessage
import smtplib

load_dotenv()

DEBUG = os.getenv("DEBUG") == "True"
MONGO_URI = os.getenv("MONGO_URI")
MONGO_DB = os.getenv("MONGO_DB")
MONGO_COLLECTION = os.getenv("MONGO_COLLECTION")

mongo_client = MongoClient(MONGO_URI)
db = mongo_client[MONGO_DB]
collection = db[MONGO_COLLECTION]
log_collection = db["fetch_logs"]

app = Flask(__name__)

OLX_API_URL = "https://olx.ba/api/search"

DEFAULT_HEADERS = {
    "User-Agent": "Mozilla/5.0",
    "Referer": "https://olx.ba",
    "Accept": "application/json",
    "Accept-Language": "en-US,en;q=0.9"
}

DEFAULT_LAND_PARAMS = {
    "category_id": 29,
    "canton": "9",
    "cities": "80,133,132,131,130,105",
    "sort_by": "date",
    "sort_order": "desc",
    "per_page": 40,
    "attr": "373032302850726f64616a6129",
    "attr_encoded": 1
}

DEFAULT_HOUSE_PARAMS = {
    "category_id": 24,
    "canton": "9",
    "cities": "80,133,132,131,130,105",
    "sort_by": "date",
    "sort_order": "desc",
    "per_page": 40,
    "attr": "373032312850726f64616a61293a373235382850617263696a616c6e6f2072656e6f766972616e2c5a612072656e6f766972616e6a652c5520697a677261646e6a6929",
    "attr_encoded": 1
}

def send_update_email(new_items_list):
    subject = "OLX.ba Update - Novi Oglasi" if new_items_list else "OLX.ba Update - Nema novih oglasa"

    if new_items_list:
        land_items = [item for item in new_items_list if item.get("item_type") == "land"]
        house_items = [item for item in new_items_list if item.get("item_type") == "house"]

        html_content = ""
        if land_items:
            html_content += "<h3>Sljedeća nova zemljišta su dodana:</h3><ul>"
            for item in land_items:
                html_content += f'''
                    <li style="margin-bottom: 10px;">
                        <strong>{item['title']}</strong> – <span style="color: red;">{item['price']}</span><br>
                        <a href="{item['url']}">{item['url']}</a>
                    </li>
                '''
            html_content += "</ul>"

        if house_items:
            html_content += "<h3>Sljedeće nove kuće su dodane:</h3><ul>"
            for item in house_items:
                html_content += f'''
                    <li style="margin-bottom: 10px;">
                        <strong>{item['title']}</strong> – <span style="color: red;">{item['price']}</span><br>
                        <a href="{item['url']}">{item['url']}</a>
                    </li>
                '''
            html_content += "</ul>"

        if not land_items and not house_items:
            html_content = "<p>Nema novih oglasa u ovom update-u.</p>"
    else:
        html_content = "<p>Nema novih oglasa u ovom update-u.</p>"

    msg = EmailMessage()
    msg['Subject'] = subject
    msg['From'] = os.getenv("EMAIL_FROM")
    msg['To'] = os.getenv("EMAIL_TO")
    msg['Cc'] = os.getenv("EMAIL_CC")
    msg.set_content("Vaš email klijent ne podržava HTML prikaz.")
    msg.add_alternative(html_content, subtype='html')

    try:
        with smtplib.SMTP(os.getenv("SMTP_HOST"), int(os.getenv("SMTP_PORT"))) as server:
            server.starttls()
            server.login(os.getenv("SMTP_USER"), os.getenv("SMTP_PASS"))
            server.send_message(msg)
            print("Email sent.")
    except Exception as e:
        print(f"Error sending email: {e}")


def fetch_page(page_num, item_type):
    params = DEFAULT_LAND_PARAMS.copy() if item_type == "land" else DEFAULT_HOUSE_PARAMS.copy()
    params["page"] = page_num
    resp = requests.get(OLX_API_URL, headers=DEFAULT_HEADERS, params=params)
    resp.raise_for_status()
    return resp.json()


def fetch_and_store_all_pages():
    total_upserts = 0
    new_items_list = []
    seen_ids = set()

    item_types = ['land', 'house']

    for item_type in item_types:
        current_page = 1
        last_page = None

        while last_page is None or current_page <= last_page:
            result = fetch_page(current_page, item_type)
            listings = result.get("data", [])
            meta = result.get("meta", {})

            if last_page is None:
                last_page = meta.get("last_page", 1)

            bulk_operations = []

            for item in listings:
                item_id = item["id"]
                seen_ids.add(item_id)  # track seen item IDs

                simplified_item = {
                    "id": item_id,
                    "title": item["title"],
                    "price": item["display_price"],
                    "raw_price": item["price"],
                    "location": item["location"],
                    "city_id": item["city_id"],
                    "area_m2": next((label["value"] for label in item.get("special_labels", []) if
                                     label.get("label") == "Kvadrata"), None),
                    "thumbnail": item.get("image"),
                    "images": item.get("images", []),
                    "url": f"https://olx.ba/artikal/{item_id}",
                    "date": item.get("date"),
                    "item_type": item_type,
                }

                existing = collection.find_one({"id": item_id})
                is_new = existing is None
                simplified_item["is_new"] = is_new

                if is_new:
                    simplified_item["created_at"] = datetime.utcnow()
                    new_items_list.append(simplified_item)

                bulk_operations.append(UpdateOne(
                    {"id": item_id},
                    {"$set": simplified_item},
                    upsert=True
                ))

            if bulk_operations:
                result = collection.bulk_write(bulk_operations)
                total_upserts += result.upserted_count + result.modified_count

            print(f"Processed page {current_page} of {last_page} for '{item_type}'")
            current_page += 1

    # Delete items no longer in the API
    deleted_result = collection.delete_many({"id": {"$nin": list(seen_ids)}})
    print(f"Removed {deleted_result.deleted_count} stale listings")

    log_collection.insert_one({
        "timestamp": datetime.utcnow(),
        "total_upserts": total_upserts,
        "new_items": len(new_items_list),
        "deleted_items": deleted_result.deleted_count
    })

    return total_upserts, len(new_items_list), new_items_list, deleted_result.deleted_count


@app.route("/api/update-listings", methods=["GET"])
def update_listings():
    # Allow only local requests (127.0.0.1 or ::1 for IPv6)
    if request.remote_addr not in ("127.0.0.1", "::1"):
        abort(403, description="Access forbidden from non-local address.")

    try:
        total_upserts, new_items, new_items_list, deleted_items = fetch_and_store_all_pages()
        send_update_email(new_items_list)
        return jsonify({
            "message": f"Upserted {total_upserts} listings.",
            "new_items": new_items,
            "deleted_items": deleted_items
        })
    except Exception as e:
        return jsonify({"error": str(e)}), 500


@app.route("/api/listings", methods=["GET"])
def list_listings():
    try:
        # Pagination
        page = int(request.args.get("page", 1))
        per_page = int(request.args.get("per_page", 20))
        skip = (page - 1) * per_page
        item_type = request.args.get("item_type", "")

        # Filters
        is_new_param = request.args.get("is_new")
        min_price = request.args.get("min_price")
        max_price = request.args.get("max_price")
        city_id_param = request.args.get("city_id")
        sort_price = request.args.get("sort_price")  # 'asc' or 'desc'

        query = {}

        if item_type:
            query["item_type"] = item_type.lower()

        if is_new_param is not None:
            query["is_new"] = is_new_param.lower() == "true"

        if min_price or max_price:
            price_query = {}
            if min_price:
                try:
                    price_query["$gte"] = int(min_price)
                except ValueError:
                    pass
            if max_price:
                try:
                    price_query["$lte"] = int(max_price)
                except ValueError:
                    pass
            if price_query:
                query["raw_price"] = price_query

        if city_id_param:
            city_ids = [int(cid.strip()) for cid in city_id_param.split(",") if cid.strip().isdigit()]
            if city_ids:
                query["city_id"] = {"$in": city_ids}

        # Sorting
        sort_criteria = [("date", -1)]
        if sort_price == "asc":
            sort_criteria = [("raw_price", 1)]
        elif sort_price == "desc":
            sort_criteria = [("raw_price", -1)]

        cursor = collection.find(query).sort(sort_criteria).skip(skip).limit(per_page)
        listings = list(cursor)

        for listing in listings:
            listing["_id"] = str(listing["_id"])

        total = collection.count_documents(query)
        return jsonify({
            "data": listings,
            "meta": {
                "page": page,
                "per_page": per_page,
                "total": total,
                "pages": (total + per_page - 1) // per_page
            }
        })
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@app.route("/api/listings/map", methods=["GET"])
def list_map_listings():
    try:
        item_type = request.args.get("item_type", "")

        query = {}
        if item_type:
            query["item_type"] = item_type.lower()

        cursor = collection.find(query, projection=['location', 'price', 'url', 'title', 'is_new'])
        map_data = list(cursor)

        for listing in map_data:
            listing["_id"] = str(listing["_id"])

        return jsonify({
            "data": map_data,
        })
    except Exception as e:
        return jsonify({"error": str(e)}), 500

@app.route("/")
def home():
    return send_from_directory("static", "index.html")


@app.route("/kuce")
def houses():
    return send_from_directory("static", "kuce.html")

if __name__ == '__main__':
    app.run(debug=DEBUG)