from flask import Blueprint, request, jsonify
from models.course import Course
from models.sub_exam import SubExam
from models.video_courses_model import VideoCourseSubject
from models.ebooks_model import Ebook
from models.mock_test_model import MockTest
from models.old_papers_model import OldPapers
from models.user_course_purchase_history import UserCoursePurchase
from datetime import datetime
from bson import ObjectId
from utils.jwt_service import jwt_required
from models.content_mapping import ContentMapping

courses_bp = Blueprint('courses', __name__)

@courses_bp.route('/get_courses_list/<string:sub_exam_id>', methods=['GET'])
@jwt_required
def get_courses_list(sub_exam_id):
    try:
        if not ObjectId.is_valid(sub_exam_id):
            return jsonify({
                "status": "false",
                "message": "Invalid sub-exam ID",
                "data": []
            }), 400

        page = int(request.args.get("page", 1))
        limit = int(request.args.get("limit", 10))
        skip = (page - 1) * limit

        base_qs = Course.objects(sub_exam_id=sub_exam_id, status=1)
        total_count = base_qs.count()

        if total_count == 0:
            return jsonify({
                "status": "false",
                "message": "No courses found for this sub-exam",
                "data": [],
                "page": page,
                "limit": limit,
                "total": 0,
                "total_pages": 0
            }), 404

        courses = list(
            base_qs.order_by('position').skip(skip).limit(limit)
        )

        course_ids = [str(c.id) for c in courses]
        counts_map = {}

        # Aggregation (use function 2 logic)
        if course_ids:
            coll = ContentMapping._get_collection()
            pipeline = [
                {"$match": {"course_id": {"$in": course_ids}}},
                {"$group": {
                    "_id": {"course_id": "$course_id", "content_type": "$content_type"},
                    "count": {"$sum": 1}
                }}
            ]
            for doc in coll.aggregate(pipeline):
                cid = doc["_id"]["course_id"]
                ctype = doc["_id"]["content_type"]
                counts_map[(cid, ctype)] = doc.get("count", 0)

        # Use function 2 helper style, but fixed content types
        def get_count(cid, *types):
            return sum(counts_map.get((cid, t), 0) for t in types)

        result = []
        for course in courses:
            cid = str(course.id)

            video_count = get_count(cid, "video")
            ebook_count = get_count(cid, "ebook")
            mock_test_count = get_count(cid, "mocktest")
            old_papers_count = get_count(cid, "oldpaper")

            result.append({
                "id": cid,
                "name": course.course_title,
                "fee": course.course_fee,
                "discounted_fee": course.discounted_fee,
                "duration": course.duration,
                "icon": course.course_image,
                "video_count": video_count,
                "ebook_count": ebook_count,
                "mock_test_count": mock_test_count,
                "old_papers_count": old_papers_count
            })

        return jsonify({
            "status": "true",
            "message": "Courses list fetched successfully",
            "data": result,
            "page": page,
            "limit": limit,
            "total": total_count,
            "total_pages": (total_count + limit - 1) // limit
        }), 200

    except Exception as e:
        return jsonify({
            "status": "false",
            "message": f"An error occurred: {str(e)}",
            "data": []
        }), 500

@courses_bp.route('/get_course_details', methods=['POST'])
@jwt_required
def get_course_details():
    try:
        
        user_id = getattr(request, "user_id", None)
        if not user_id:
            return jsonify({"status": False, "message": "Invalid user id"}), 401

        data = request.get_json()
        course_id = data.get('course_id')

        if not course_id or not ObjectId.is_valid(course_id):
            return jsonify({
                "status": "false",
                "message": "Invalid or missing course ID",
                "data": {}
            }), 400

        course = Course.objects(id=course_id, status=1).first()
        if not course:
            return jsonify({
                "status": "false",
                "message": "Course not found",
                "data": {}
            }), 404

        coll = ContentMapping._get_collection()
        pipeline = [
            {"$match": {"course_id": str(course.id)}},
            {"$group": {"_id": "$content_type", "count": {"$sum": 1}}}
        ]
        agg_cursor = coll.aggregate(pipeline)
        counts_map = {doc["_id"]: doc.get("count", 0) for doc in agg_cursor}

        def count_for(*keys):
            return sum(counts_map.get(k, 0) for k in keys)

        video_count = count_for("video", "videos")
        ebook_count = count_for("ebook", "ebooks")
        mock_test_count = count_for("mocktest", "mock_test", "mocktests", "mock-tests")
        old_papers_count = count_for("oldpaper", "oldpapers", "old_paper", "old_papers")

        course_json = course.to_mongo().to_dict()

        course_json["id"] = str(course_json.pop("_id"))

        course_json["video_count"] = video_count
        course_json["ebook_count"] = ebook_count
        course_json["mock_test_count"] = mock_test_count
        course_json["old_papers_count"] = old_papers_count
        course_json["is_purchased"] = 0
        course_json["is_expired"] = 0

        if user_id:
            purchase = UserCoursePurchase.objects(
                user_id=ObjectId(user_id),
                course_id=course.id,
                status=1
            ).order_by('-purchase_date').first()
            if purchase:
                course_json["is_purchased"] = 1
                expiry_days = course.duration if getattr(course, "duration", None) else 0
                if purchase.purchase_date and expiry_days > 0:
                    if (datetime.utcnow() - purchase.purchase_date).days > expiry_days:
                        course_json["is_expired"] = 1


        def sanitize(value):
            if isinstance(value, ObjectId):
                return str(value)
            if isinstance(value, datetime):
                return value.isoformat()
            if isinstance(value, dict):
                return {k: sanitize(v) for k, v in value.items()}
            if isinstance(value, list):
                return [sanitize(v) for v in value]
            return value

        safe_course_json = sanitize(course_json)

        return jsonify({
            "status": "true",
            "message": "Course details fetched successfully",
            "data": safe_course_json
        }), 200

    except Exception as e:
        return jsonify({
            "status": "false",
            "message": f"An error occurred: {str(e)}",
            "data": {}
        }), 500


@courses_bp.route('/get_courses_list_home/<string:sub_exam_id>', methods=['GET'])
def get_courses_list_home(sub_exam_id):
    try:
        if not ObjectId.is_valid(sub_exam_id):
            return jsonify({
                "status": "false",
                "message": "Invalid sub-exam ID",
                "data": []
            }), 400

        page = int(request.args.get("page", 1))
        limit = int(request.args.get("limit", 10))
        skip = (page - 1) * limit

        base_qs = Course.objects(sub_exam_id=sub_exam_id, status=1)
        total_count = base_qs.count()

        if total_count == 0:
            return jsonify({
                "status": "false",
                "message": "No courses found for this sub-exam",
                "data": [],
                "page": page,
                "limit": limit,
                "total": 0,
                "total_pages": 0
            }), 404

        courses = list(
            base_qs.order_by('position').skip(skip).limit(limit)
        )

        course_ids = [str(c.id) for c in courses]
        counts_map = {}

        # Aggregation (same as function 1)
        if course_ids:
            coll = ContentMapping._get_collection()
            pipeline = [
                {"$match": {"course_id": {"$in": course_ids}}},
                {"$group": {
                    "_id": {"course_id": "$course_id", "content_type": "$content_type"},
                    "count": {"$sum": 1}
                }}
            ]
            for doc in coll.aggregate(pipeline):
                cid = doc["_id"]["course_id"]
                ctype = doc["_id"]["content_type"]
                counts_map[(cid, ctype)] = doc.get("count", 0)

        # Use function 2 helper but fixed types
        def get_count(cid, *types):
            return sum(counts_map.get((cid, t), 0) for t in types)

        result = []
        for course in courses:
            cid = str(course.id)

            video_count = get_count(cid, "video")
            ebook_count = get_count(cid, "ebook")
            mock_test_count = get_count(cid, "mocktest")
            old_papers_count = get_count(cid, "oldpaper")

            result.append({
                "id": cid,
                "name": course.course_title,
                "fee": course.course_fee,
                "discounted_fee": course.discounted_fee,
                "duration": course.duration,
                "icon": course.course_image,
                "video_count": video_count,
                "ebook_count": ebook_count,
                "mock_test_count": mock_test_count,
                "old_papers_count": old_papers_count
            })

        return jsonify({
            "status": "true",
            "message": "Courses list fetched successfully",
            "data": result,
            "page": page,
            "limit": limit,
            "total": total_count,
            "total_pages": (total_count + limit - 1) // limit
        }), 200

    except Exception as e:
        return jsonify({
            "status": "false",
            "message": f"An error occurred: {str(e)}",
            "data": []
        }), 500


@courses_bp.route('/get_course_details_home', methods=['POST'])
def get_course_details_home():
    try:
        data = request.get_json()
        course_id = data.get('course_id')
        user_id = data.get('user_id')

        if not course_id or not ObjectId.is_valid(course_id):
            return jsonify({
                "status": "false",
                "message": "Invalid or missing course ID",
                "data": {}
            }), 400

        course = Course.objects(id=course_id, status=1).first()
        if not course:
            return jsonify({
                "status": "false",
                "message": "Course not found",
                "data": {}
            }), 404

        coll = ContentMapping._get_collection()
        pipeline = [
            {"$match": {"course_id": str(course.id)}},
            {"$group": {"_id": "$content_type", "count": {"$sum": 1}}}
        ]
        agg_cursor = coll.aggregate(pipeline)
        counts_map = {doc["_id"]: doc.get("count", 0) for doc in agg_cursor}

        def count_for(*keys):
            return sum(counts_map.get(k, 0) for k in keys)

        video_count = count_for("video", "videos")
        ebook_count = count_for("ebook", "ebooks")
        mock_test_count = count_for("mocktest", "mock_test", "mocktests", "mock-tests")
        old_papers_count = count_for("oldpaper", "oldpapers", "old_paper", "old_papers")


        course_json = course.to_mongo().to_dict()

        course_json["id"] = str(course_json.pop("_id"))

        course_json["video_count"] = video_count
        course_json["ebook_count"] = ebook_count
        course_json["mock_test_count"] = mock_test_count
        course_json["old_papers_count"] = old_papers_count
        course_json["is_purchased"] = 0
        course_json["is_expired"] = 0

        if user_id and ObjectId.is_valid(user_id):
            purchase = UserCoursePurchase.objects(
                user_id=ObjectId(user_id),
                course_id=course.id,
                status=1
            ).order_by('-purchase_date').first()
            if purchase:
                course_json["is_purchased"] = 1
                expiry_days = course.duration if getattr(course, "duration", None) else 0
                if purchase.purchase_date and expiry_days > 0:
                    if (datetime.utcnow() - purchase.purchase_date).days > expiry_days:
                        course_json["is_expired"] = 1
        def sanitize(value):
            if isinstance(value, ObjectId):
                return str(value)
            if isinstance(value, datetime):
                return value.isoformat()
            if isinstance(value, dict):
                return {k: sanitize(v) for k, v in value.items()}
            if isinstance(value, list):
                return [sanitize(v) for v in value]
            return value

        safe_course_json = sanitize(course_json)

        return jsonify({
            "status": "true",
            "message": "Course details fetched successfully",
            "data": safe_course_json
        }), 200

    except Exception as e:
        return jsonify({
            "status": "false",
            "message": f"An error occurred: {str(e)}",
            "data": {}
        }), 500

@courses_bp.route('/search-courses', methods=['POST'])
def search_courses():
    """
    POST /search-courses
    Body (JSON or form):
        {
            "search": "python"     # or "query": "python"
        }

    Pagination (query params):
        ?page=1&limit=10

    Returns active courses whose course_title contains the search text
    (case-insensitive), with pagination.
    """
    # ---- Read search text from JSON or form ----
    if request.is_json:
        payload = request.get_json(silent=True) or {}
        search_text = (payload.get("search") or payload.get("query") or "").strip()
    else:
        search_text = (request.form.get("search") or request.form.get("query") or "").strip()

    if not search_text:
        return jsonify({
            "status": False,
            "message": "Search text is required (use 'search' or 'query' field).",
            "count": 0,
            "courses": [],
            "page": 1,
            "limit": 10,
            "total": 0,
            "total_pages": 0
        }), 400

    # ---- Pagination params (same style as other APIs) ----
    page = int(request.args.get("page", 1))
    limit = int(request.args.get("limit", 3))
    skip = (page - 1) * limit

    # ---- Base query: case-insensitive partial match + active courses ----
    base_qs = Course.objects(
        course_title__icontains=search_text,
        status=1
    )

    total_count = base_qs.count()

    # Apply ordering + pagination
    matching_courses = (
        base_qs
        .order_by("position", "-created_date")
        .skip(skip)
        .limit(limit)
    )

    courses_data = [course.to_json() for course in matching_courses]

    return jsonify({
        "status": True,
        "message": "Courses found." if courses_data else "No courses found for given search text.",
        "trending_searches" : ["rrb cleark","ssc gd", "rrb ntpc", "ctet", "viral"],
        "count": len(courses_data),              # count in this page
        "courses": courses_data,
        "page": page,
        "limit": limit,
        "total": total_count,                    # total matching courses
        "total_pages": (total_count + limit - 1) // limit
    }), 200