import os
from functools import wraps

from flask import abort, flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required
from werkzeug.utils import secure_filename

from ..data import CRITERIA, PILLARS, SCALES_LABELS
from ..extensions import db
from ..models import Article, Score, Solution, Tag
from ..utils import allowed_file, save_logo
from . import bp


def admin_required(f):
    @wraps(f)
    def decorated_function(*args, **kwargs):
        if not current_user.is_authenticated or not current_user.is_admin:
            abort(403)
        return f(*args, **kwargs)

    return decorated_function


@bp.route("/admin/dashboard")
@login_required
def admin_dashboard():
    # Only allow admin access
    if not current_user.is_admin:
        abort(403)

    pending_solutions = Solution.query.filter_by(is_validated=False).all()
    # Fetch all articles to manage them
    articles = Article.query.order_by(Article.created_at.desc()).all()

    return render_template(
        "admin_dashboard.html", solutions=pending_solutions, articles=articles
    )


@bp.route("/admin/articles/create", methods=["GET", "POST"])
@login_required
def create_article():
    if not current_user.is_admin:
        abort(403)

    if request.method == "POST":
        title = request.form.get("title")
        content = request.form.get("content")
        slug = request.form.get("slug")

        # Simple slug generation if empty
        if not slug:
            slug = title.lower().replace(" ", "-")

        new_article = Article(
            title=title,
            slug=slug,
            content=content,
            author_id=current_user.id,
            published=True,  # Auto publish for now, can be changed
        )

        db.session.add(new_article)
        try:
            db.session.commit()
            flash("Article créé avec succès!", "success")
            return redirect(url_for("admin.admin_dashboard"))
        except:
            db.session.rollback()
            flash("Erreur lors de la création (slug peut-être déjà pris)", "error")

    return render_template("admin/create_article.html")


@bp.route("/admin/articles/edit/<int:id>", methods=["GET", "POST"])
@login_required
def edit_article(id):
    if not current_user.is_admin:
        abort(403)

    article = Article.query.get_or_404(id)

    if request.method == "POST":
        article.title = request.form.get("title")
        article.content = request.form.get("content")
        # Check slug uniqueness only if changed
        new_slug = request.form.get("slug")
        if new_slug != article.slug:
            existing = Article.query.filter_by(slug=new_slug).first()
            if existing:
                flash("Slug déjà utilisé", "error")
                return render_template("admin/edit_article.html", article=article)
            article.slug = new_slug

        article.published = "published" in request.form

        try:
            db.session.commit()
            flash("Article mis à jour!", "success")
            return redirect(url_for("admin.admin_dashboard"))
        except:
            db.session.rollback()
            flash("Erreur lors de la mise à jour", "error")

    return render_template("admin/edit_article.html", article=article)


@bp.route("/admin/articles/delete/<int:id>")
@login_required
def delete_article(id):
    if not current_user.is_admin:
        abort(403)

    article = Article.query.get_or_404(id)
    db.session.delete(article)
    db.session.commit()
    flash("Article supprimé", "success")
    return redirect(url_for("admin.admin_dashboard"))


@login_required
@admin_required
@bp.route("/validate/<int:id>")
def validate_solution(id):
    solution = Solution.query.get_or_404(id)
    solution.is_validated = True
    db.session.commit()
    flash(f"La solution '{solution.name}' a été publiée avec succès.", "success")
    return redirect(url_for("admin.admin_dashboard"))


@bp.route("/delete/<int:id>")
@login_required
@admin_required
def delete_solution(id):
    solution = Solution.query.get_or_404(id)
    db.session.delete(solution)
    db.session.commit()
    flash(f"La solution '{solution.name}' a été supprimée.", "contrast")
    return redirect(url_for("admin.admin_dashboard"))


@bp.route("/edit/<int:id>", methods=["GET", "POST"])
@login_required
@admin_required
def edit_solution(id):
    solution = Solution.query.get_or_404(id)

    if request.method == "POST":
        solution.name = request.form.get("name")
        solution.description = request.form.get("description")
        solution.website = request.form.get("website")

        solution.origin = request.form.get("origin")
        solution.license = request.form.get("license")
        solution.platforms = request.form.get("platforms")

        logo = request.files.get("logo")
        if logo and logo.filename != "" and allowed_file(logo.filename):
            solution.logo_filename = save_logo(logo)

        tags_input = request.form.get("tags")
        if tags_input is not None:
            solution.tags = []
            tag_names = [t.strip() for t in tags_input.split(",") if t.strip()]
            for tag_name in tag_names:
                tag = Tag.query.filter_by(name=tag_name).first()
                if not tag:
                    tag = Tag(name=tag_name)
                    db.session.add(tag)
                solution.tags.append(tag)

        current_scores = {s.criterion_id: s for s in solution.scores}

        for p_id, c_id, title, desc, choices in CRITERIA:
            val = request.form.get(f"rating_{c_id}")
            justif = request.form.get(f"justification_{c_id}")
            src = request.form.get(f"source_{c_id}")

            if val is not None:
                if c_id in current_scores:
                    score = current_scores[c_id]
                    score.value = int(val)
                    score.justification = justif
                    score.source = src
                else:
                    new_score = Score(
                        solution_id=solution.id,
                        criterion_id=c_id,
                        value=int(val),
                        justification=justif,
                        source=src,
                    )
                    db.session.add(new_score)

        db.session.commit()
        flash("Solution mise à jour avec succès !", "success")
        return redirect(url_for("main.solution_detail", id=solution.id))

    scores_map = {s.criterion_id: s for s in solution.scores}

    return render_template(
        "edit.html",
        solution=solution,
        scores_map=scores_map,
        pillars=PILLARS,
        criteria=CRITERIA,
        scales_labels=SCALES_LABELS,
    )
