from datetime import datetime

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

from app.extensions import db, login_manager
from app.models import User
from app.auth.forms import RegisterForm, LoginForm, ChangePasswordForm

auth_bp = Blueprint("auth", __name__, url_prefix="/auth", template_folder="../templates/auth")


@login_manager.user_loader
def load_user(user_id):
    return db.session.get(User, int(user_id))


def _post_login_redirect():
    if current_user.is_admin():
        return redirect(url_for("admin.index"))
    if not current_user.patients:
        return redirect(url_for("profiles.new_profile"))
    return redirect(url_for("summary.view"))


@auth_bp.route("/registro", methods=["GET", "POST"])
def register():
    if current_user.is_authenticated:
        return _post_login_redirect()

    form = RegisterForm()
    if form.validate_on_submit():
        if User.query.filter_by(email=form.email.data.lower()).first():
            flash("Ya existe una cuenta con ese correo.", "danger")
            return render_template("auth/register.html", form=form)

        user = User(email=form.email.data.lower(), role="patient")
        user.set_password(form.password.data)
        user.accepted_terms_at = datetime.utcnow()
        db.session.add(user)
        db.session.commit()

        login_user(user)
        flash(
            "Cuenta creada. Ahora crea el primer perfil (el tuyo, o el de la "
            "persona que vas a cuidar).",
            "success",
        )
        return redirect(url_for("profiles.new_profile"))

    return render_template("auth/register.html", form=form)


@auth_bp.route("/login", methods=["GET", "POST"])
def login():
    if current_user.is_authenticated:
        return _post_login_redirect()

    form = LoginForm()
    if form.validate_on_submit():
        user = User.query.filter_by(email=form.email.data.lower()).first()
        if user is None or not user.check_password(form.password.data):
            flash("Correo o contraseña incorrectos.", "danger")
            return render_template("auth/login.html", form=form)

        if not login_user(user):
            flash("Esta cuenta está desactivada. Contacta a un administrador.", "danger")
            return render_template("auth/login.html", form=form)

        return _post_login_redirect()

    return render_template("auth/login.html", form=form)


@auth_bp.route("/logout")
@login_required
def logout():
    logout_user()
    return redirect(url_for("auth.login"))


@auth_bp.route("/cambiar-password", methods=["GET", "POST"])
@login_required
def change_password():
    form = ChangePasswordForm()
    if form.validate_on_submit():
        if not current_user.check_password(form.current_password.data):
            flash("La contraseña actual no es correcta.", "danger")
            return render_template("auth/change_password.html", form=form)

        current_user.set_password(form.new_password.data)
        db.session.commit()
        flash("Contraseña actualizada.", "success")
        return _post_login_redirect()

    return render_template("auth/change_password.html", form=form)


@auth_bp.route("/telegram", methods=["GET", "POST"])
@login_required
def link_telegram():
    if not current_app.config.get("TELEGRAM_ENABLED"):
        flash("El canal de Telegram todavía no está activo.", "info")
        return redirect(url_for("auth.change_password"))

    if request.method == "POST":
        code = current_user.generate_telegram_link_code()
        db.session.commit()
        flash("Nuevo código generado. Válido por 15 minutos.", "success")

    return render_template(
        "auth/telegram.html",
        bot_username=current_app.config.get("TELEGRAM_BOT_USERNAME"),
    )


@auth_bp.route("/telegram/desvincular", methods=["POST"])
@login_required
def unlink_telegram():
    current_user.telegram_chat_id = None
    db.session.commit()
    flash("Telegram desvinculado.", "success")
    return redirect(url_for("auth.link_telegram"))
