from datetime import timedelta

from flask import Blueprint, flash, redirect, render_template, request, session, url_for
from flask_login import current_user, login_required, login_user, logout_user

from .extensions import db
from .models import User
from .policy import utcnow
from .services import audit


bp = Blueprint("auth", __name__)
_attempts = {}


def _login_key():
    return f"{request.remote_addr}:{request.form.get('username', '').lower().strip()}"


@bp.route("/login", methods=["GET", "POST"])
def login():
    if current_user.is_authenticated:
        return redirect(url_for("main.dashboard"))
    if request.method == "POST":
        key = _login_key()
        now = utcnow()
        recent = [value for value in _attempts.get(key, []) if now - value < timedelta(minutes=15)]
        if len(recent) >= 8:
            flash("Too many failed attempts. Please wait 15 minutes and try again.", "danger")
            return render_template("login.html"), 429

        username = request.form.get("username", "").lower().strip()
        password = request.form.get("password", "")
        user = db.session.scalar(db.select(User).where(User.username == username))
        if not user or not user.is_active or not user.check_password(password):
            recent.append(now)
            _attempts[key] = recent
            audit("LOGIN_FAILED", "User", getattr(user, "id", None), f"Username: {username}", actor=None)
            db.session.commit()
            flash("Invalid username or password.", "danger")
            return render_template("login.html"), 401

        _attempts.pop(key, None)
        login_user(user, remember=bool(request.form.get("remember")))
        session.permanent = True
        user.last_login_at = now
        audit("LOGIN", "User", user.id, actor=user)
        db.session.commit()
        next_url = request.args.get("next", "")
        if not next_url.startswith("/") or next_url.startswith("//"):
            next_url = url_for("main.dashboard")
        return redirect(next_url)
    return render_template("login.html")


@bp.post("/logout")
@login_required
def logout():
    audit("LOGOUT", "User", current_user.id)
    db.session.commit()
    logout_user()
    return redirect(url_for("auth.login"))


@bp.route("/my-account", methods=["GET", "POST"])
@login_required
def account():
    if request.method == "POST":
        action = request.form.get("action")
        if action == "profile":
            current_user.email = request.form.get("email", "").strip() or None
            current_user.mobile = request.form.get("mobile", "").strip() or None
            audit("PROFILE_UPDATED", "User", current_user.id)
            db.session.commit()
            flash("Account details updated.", "success")
        elif action == "password":
            old = request.form.get("current_password", "")
            new = request.form.get("new_password", "")
            confirm = request.form.get("confirm_password", "")
            if not current_user.check_password(old):
                flash("Current password is incorrect.", "danger")
            elif len(new) < 12:
                flash("New password must contain at least 12 characters.", "danger")
            elif new != confirm:
                flash("New password confirmation does not match.", "danger")
            else:
                current_user.set_password(new)
                current_user.must_change_password = False
                audit("PASSWORD_CHANGED", "User", current_user.id)
                db.session.commit()
                flash("Password changed successfully.", "success")
        return redirect(url_for("auth.account"))
    return render_template("account.html")
