import os

from flask import (
    Blueprint,
    render_template,
    request,
    redirect,
    url_for,
    flash,
    session,
    current_app
)

from extensions import db

from models import (
    Category,
    Product,
    ProductImage,
    ProductVariant,
    StockMovement,
    CartItem,
    OrderItem,
    Review
)


category_bp = Blueprint("category", __name__)


# =========================================================
# DELETE CATEGORY
# =========================================================

@category_bp.route(
    "/admin/categories/<int:category_id>/delete",
    methods=["POST"]
)
def delete_category(category_id):

    if "user_id" not in session:
        return redirect(
            url_for("auth.login")
        )

    if session.get("role") not in ["owner", "admin"]:
        flash(
            "You do not have permission to delete categories.",
            "error"
        )
        return redirect(
            url_for("dashboard.admin_dashboard")
        )

    category = db.session.get(
        Category,
        category_id
    )

    if not category:
        flash(
            "Category not found.",
            "error"
        )
        return redirect(
            url_for("category.admin_categories")
        )

    product_count = Product.query.filter_by(
        category_id=category.id
    ).count()

    if product_count > 0:

        flash(
            "This category cannot be deleted because it has "
            f"{product_count} product(s) assigned to it. "
            "Move the products to another category first.",
            "error"
        )

        return redirect(
            url_for("category.admin_categories")
        )

    try:

        db.session.delete(
            category
        )

        db.session.commit()

        flash(
            "Category deleted successfully.",
            "success"
        )

    except Exception:

        db.session.rollback()

        flash(
            "The category could not be deleted.",
            "error"
        )

    return redirect(
        url_for("category.admin_categories")
    )


# =========================================================
# DELETE PRODUCT
# =========================================================

@category_bp.route(
    "/admin/products/<int:product_id>/delete",
    methods=["POST"]
)
def delete_product(product_id):

    if "user_id" not in session:
        return redirect(
            url_for("auth.login")
        )

    if session.get("role") not in ["owner", "admin"]:
        flash(
            "You do not have permission to delete products.",
            "error"
        )
        return redirect(
            url_for("dashboard.admin_dashboard")
        )

    product = db.session.get(
        Product,
        product_id
    )

    if not product:
        flash(
            "Product not found.",
            "error"
        )
        return redirect(
            url_for("product.admin_products")
        )

    # -----------------------------------------------------
    # CHECK ORDER HISTORY
    # -----------------------------------------------------

    variant_ids = [
        variant.id
        for variant in ProductVariant.query.filter_by(
            product_id=product.id
        ).all()
    ]

    has_order_history = False

    if variant_ids:

        has_order_history = (
            OrderItem.query.filter(
                OrderItem.variant_id.in_(variant_ids)
            ).first()
            is not None
        )

    # -----------------------------------------------------
    # PRESERVE PRODUCTS WITH ORDER HISTORY
    # -----------------------------------------------------

    if has_order_history:

        product.is_active = False

        try:

            db.session.commit()

            flash(
                "This product has order history, so it was "
                "deactivated instead of permanently deleted.",
                "success"
            )

        except Exception:

            db.session.rollback()

            flash(
                "The product could not be deactivated.",
                "error"
            )

        return redirect(
            url_for("product.admin_products")
        )

    # -----------------------------------------------------
    # PRODUCT HAS NO ORDER HISTORY
    # -----------------------------------------------------

    image_filenames = [
        image.filename
        for image in ProductImage.query.filter_by(
            product_id=product.id
        ).all()
    ]

    try:

        # -------------------------------------------------
        # DELETE CART ITEMS
        # -------------------------------------------------

        if variant_ids:

            CartItem.query.filter(
                CartItem.variant_id.in_(variant_ids)
            ).delete(
                synchronize_session=False
            )

        # -------------------------------------------------
        # DELETE STOCK MOVEMENTS
        # -------------------------------------------------

        if variant_ids:

            StockMovement.query.filter(
                StockMovement.variant_id.in_(variant_ids)
            ).delete(
                synchronize_session=False
            )

        # -------------------------------------------------
        # DELETE REVIEWS
        # -------------------------------------------------

        Review.query.filter_by(
            product_id=product.id
        ).delete(
            synchronize_session=False
        )

        # -------------------------------------------------
        # DELETE PRODUCT IMAGES
        # -------------------------------------------------

        ProductImage.query.filter_by(
            product_id=product.id
        ).delete(
            synchronize_session=False
        )

        # -------------------------------------------------
        # DELETE VARIANTS
        # -------------------------------------------------

        ProductVariant.query.filter_by(
            product_id=product.id
        ).delete(
            synchronize_session=False
        )

        # -------------------------------------------------
        # DELETE PRODUCT
        # -------------------------------------------------

        db.session.delete(
            product
        )

        db.session.commit()

    except Exception:

        db.session.rollback()

        flash(
            "The product could not be deleted.",
            "error"
        )

        return redirect(
            url_for("product.admin_products")
        )

    # -----------------------------------------------------
    # REMOVE IMAGE FILES
    # -----------------------------------------------------

    upload_folder = os.path.join(
        current_app.root_path,
        "static",
        "product_images"
    )

    for filename in image_filenames:

        file_path = os.path.join(
            upload_folder,
            filename
        )

        try:

            if os.path.exists(file_path):
                os.remove(file_path)

        except Exception:
            pass

    flash(
        "Product deleted successfully.",
        "success"
    )

    return redirect(
        url_for("product.admin_products")
    )


# =========================================================
# EDIT CATEGORY
# =========================================================

@category_bp.route(
    "/admin/categories/<int:category_id>/edit",
    methods=["GET", "POST"]
)
def edit_category(category_id):

    if "user_id" not in session:
        return redirect(
            url_for("auth.login")
        )

    if session.get("role") not in ["owner", "admin"]:
        flash(
            "You do not have permission to edit categories.",
            "error"
        )
        return redirect(
            url_for("dashboard.admin_dashboard")
        )

    category = db.session.get(
        Category,
        category_id
    )

    if not category:
        flash(
            "Category not found.",
            "error"
        )
        return redirect(
            url_for("category.admin_categories")
        )

    if request.method == "GET":

        return render_template(
            "admin/edit_category.html",
            category=category
        )

    name = request.form.get(
        "name",
        ""
    ).strip()

    description = request.form.get(
        "description",
        ""
    ).strip()

    if not name:

        flash(
            "Category name is required.",
            "error"
        )

        return redirect(
            url_for(
                "category.edit_category",
                category_id=category.id
            )
        )

    existing_category = Category.query.filter(
        db.func.lower(Category.name) == name.lower(),
        Category.id != category.id
    ).first()

    if existing_category:

        flash(
            "A category with this name already exists.",
            "error"
        )

        return redirect(
            url_for(
                "category.edit_category",
                category_id=category.id
            )
        )

    category.name = name

    category.description = (
        description or None
    )

    try:

        db.session.commit()

        flash(
            "Category updated successfully.",
            "success"
        )

    except Exception:

        db.session.rollback()

        flash(
            "The category could not be updated.",
            "error"
        )

    return redirect(
        url_for("category.admin_categories")
    )


# =========================================================
# ADD CATEGORY
# =========================================================

@category_bp.route(
    "/admin/categories/add",
    methods=["GET", "POST"]
)
def add_category():

    if "user_id" not in session:
        return redirect(
            url_for("auth.login")
        )

    if session.get("role") not in ["owner", "admin"]:
        flash(
            "You do not have permission to add categories.",
            "error"
        )
        return redirect(
            url_for("dashboard.admin_dashboard")
        )

    if request.method == "GET":

        return render_template(
            "admin/add_category.html"
        )

    name = request.form.get(
        "name",
        ""
    ).strip()

    description = request.form.get(
        "description",
        ""
    ).strip()

    if not name:

        flash(
            "Category name is required.",
            "error"
        )

        return redirect(
            url_for("category.add_category")
        )

    existing_category = Category.query.filter(
        db.func.lower(Category.name) == name.lower()
    ).first()

    if existing_category:

        flash(
            "A category with this name already exists.",
            "error"
        )

        return redirect(
            url_for("category.add_category")
        )

    category = Category(
        name=name,
        description=description or None,
        is_active=True
    )

    db.session.add(
        category
    )

    try:

        db.session.commit()

        flash(
            "Category added successfully.",
            "success"
        )

    except Exception:

        db.session.rollback()

        flash(
            "The category could not be added.",
            "error"
        )

    return redirect(
        url_for("category.admin_categories")
    )


# =========================================================
# TOGGLE CATEGORY STATUS
# =========================================================

@category_bp.route(
    "/admin/categories/<int:category_id>/toggle-status",
    methods=["POST"]
)
def toggle_category_status(category_id):

    if "user_id" not in session:
        return redirect(
            url_for("auth.login")
        )

    if session.get("role") not in ["owner", "admin"]:
        flash(
            "You do not have permission to change category status.",
            "error"
        )
        return redirect(
            url_for("dashboard.admin_dashboard")
        )

    category = db.session.get(
        Category,
        category_id
    )

    if not category:

        flash(
            "Category not found.",
            "error"
        )

        return redirect(
            url_for("category.admin_categories")
        )

    category.is_active = not category.is_active

    try:

        db.session.commit()

        if category.is_active:

            flash(
                "Category activated successfully.",
                "success"
            )

        else:

            flash(
                "Category deactivated successfully.",
                "success"
            )

    except Exception:

        db.session.rollback()

        flash(
            "The category status could not be changed.",
            "error"
        )

    return redirect(
        url_for("category.admin_categories")
    )


# =========================================================
# ADMIN CATEGORIES
# =========================================================

@category_bp.route(
    "/admin/categories"
)
def admin_categories():

    if "user_id" not in session:
        return redirect(
            url_for("auth.login")
        )

    if session.get("role") not in ["owner", "admin"]:
        flash(
            "You do not have permission to view categories.",
            "error"
        )
        return redirect(
            url_for("dashboard.admin_dashboard")
        )

    categories = Category.query.order_by(
        Category.name.asc()
    ).all()

    return render_template(
        "admin/categories.html",
        categories=categories
    )