import secrets
import string
import uuid
from datetime import datetime, timedelta

from flask import Blueprint, flash, redirect, render_template, request, url_for
from flask_login import current_user, login_required, login_user, logout_user
from flask_mailman import EmailMessage
from sqlalchemy import func, or_, select

from web_application import bcrypt, db
from web_application.constants import roles
from web_application.kullanici.forms import (
    GirisFormu,
    KayitFormu,
    KullaniciAdiDegistirmeFormu,
    KullaniciParolasiDegistirmeFormu,
    ParolamiUnuttumFormu,
    ParolaSifirlamaFormu,
)
from web_application.models import Kullanici, ParolaSifirlamaTokeni

kullanici = Blueprint(
    "kullanici",
    __name__,
    template_folder="templates",
    static_folder="static",
    url_prefix="/kullanici",
)


def parola_sifirlama_tokeni_olustur():
    # Create a sequence of all uppercase letters and digits
    karakterler = string.ascii_letters + string.digits + "-_!@#$%^&*()"

    # Generate a 64-character random string
    rastgele_metin = "".join(secrets.choice(karakterler) for _ in range(64))

    return rastgele_metin


@kullanici.route("/kaydol", methods=["GET", "POST"])
def kaydol():
    if current_user.is_authenticated:
        return redirect(url_for("ana.index"))

    form = KayitFormu()

    if request.method == "POST":
        if form.validate_on_submit():
            k_sql = select(Kullanici).where(
                or_(
                    Kullanici.eposta == form.eposta.data,
                    Kullanici.telefon == form.telefon.data,
                )
            )
            kullanici = db.session.execute(k_sql).scalars().first()

            print(form.telefon.data)
            print(form.eposta.data)

            if kullanici:
                flash("Bu e-posta adresi ya da telefon zaten kayıtlı.", "danger")
                return redirect(url_for("kullanici.kaydol"))

            yeni_kullanici = Kullanici(
                ad_soyad=form.ad_soyad.data,
                eposta=form.eposta.data,
                telefon=form.telefon.data,
                parola=bcrypt.generate_password_hash(form.parola.data),
                rol_num=2,  # Default role for regular users
            )
            db.session.add(yeni_kullanici)
            try:
                db.session.commit()
                flash("Kayıt işlemi başarılı. Lütfen giriş yapın.", "success")
                return redirect(url_for("kullanici.giris"))
            except Exception as e:
                db.session.rollback()
                flash(f"Kayıt sırasında bir hata oluştu: {e}", "danger")

    data = {"title": "Kullanıcı Kaydı", "form": form}
    return render_template("kullanici/kaydol.html", **data)


@kullanici.route("/admin-olustur")
def admin_olustur():
    kullanici_sayisi_sql = select(func.count()).select_from(Kullanici)
    kullanici_sayisi = db.session.execute(kullanici_sayisi_sql).scalars().first()
    if kullanici_sayisi == 0:
        admin = Kullanici(
            ad_soyad="System Admin",
            telefon="09999999999",
            eposta="dinceraydic@gmail.com",
            parola=bcrypt.generate_password_hash("admin"),
            rol_num=0,
        )
        db.session.add(admin)

        try:
            db.session.commit()
            flash(
                "Bir yönetici hesabı oluşturdunuz. Lütfen, giriş yapın ve parolanızı değiştirin.",
                "success",
            )
            return redirect(url_for("ana.index"))
        except Exception as e:
            db.session.rollback()
            flash(
                f"Bir hata oluştu. {e}",
                "danger",
            )
            return redirect(url_for("ana.index"))
    else:
        flash("Admin User oluşturken hatalı bir işlem gerçekleştirdiniz. ", "danger")
        return redirect(url_for("ana.index"))


@kullanici.route("/giris", methods=["GET", "POST"])
def giris():
    if current_user.is_authenticated:
        return redirect(url_for("ana.index"))
    form = GirisFormu()
    if request.method == "POST":
        if form.validate_on_submit():
            print("validated")
            k_sql = select(Kullanici).where(Kullanici.eposta == form.eposta.data)
            kullanici = db.session.execute(k_sql).scalars().first()

            if kullanici is None or not bcrypt.check_password_hash(
                kullanici.parola, form.parola.data
            ):
                flash("Hatalı telefon numarası ya da parola girdiniz.", "danger")
                return redirect(url_for("kullanici.giris"))

            login_user(kullanici, remember=form.beni_hatirla.data)

            ## varsa reset token'i sil
            if kullanici.sifirlama_tokeni:
                db.session.delete(kullanici.sifirlama_tokeni)
                db.session.commit()
            flash(
                "Başarılı bir şekilde giriş yaptınız.",
                "success",
            )
            next_page = request.args.get("next")
            return redirect(next_page) if next_page else redirect(url_for("ana.index"))
    if form.errors:
        print("Validation Errors:", form.errors)
    data = {"title": "Giriş", "form": form}
    return render_template("kullanici/giris.html", **data)


@kullanici.route("/parolami-unuttum", methods=["GET", "POST"])
def parolami_unuttum():
    if current_user.is_authenticated:
        return redirect(url_for("ana.index"))
    form = ParolamiUnuttumFormu()
    if request.method == "POST":
        if form.validate_on_submit():
            k_sql = select(Kullanici).where(Kullanici.eposta == form.eposta.data)
            kullanici = db.session.execute(k_sql).scalars().first()
            if kullanici:
                parola_sifirlama_tokeni = parola_sifirlama_tokeni_olustur()
                yeni_token = ParolaSifirlamaTokeni(
                    kullanici_id=kullanici.id,
                    token=parola_sifirlama_tokeni,
                )
                db.session.add(yeni_token)
                db.session.commit()
                # Here you would typically send an email with a reset link
                mesaj = EmailMessage(
                    subject="Parola Sıfırlama Talebinizi Aldık",
                    body=f"""Parola sıfırlama talebiniz alınmıştır. Lütfen aşağıdaki linke tıklayarak yeni parolanızı oluşturun.
                    <br><br>Link: <a href="{url_for("kullanici.kullanici_parolasi_degistir", token=parola_sifirlama_tokeni, _external=True)}">Parola Sıfırlama Linki</a>
                    <br><br>Bu işlemi yapmadıysanız, bu e-postayı dikkate almayabilirsiniz.""",
                    from_email="donotreply@scholars.tr",
                    to=[form.eposta.data],
                )
                mesaj.content_subtype = "html"
                res = mesaj.send()
                if res:
                    flash(
                        "Parola sıfırlama talebiniz alınmıştır. E-posta adresinize bir link gönderilmiştir.",
                        "success",
                    )
                    return redirect(
                        url_for("kullanici.parola_sifirlama_maili_gonderildi")
                    )
                else:
                    flash(
                        "Parola sıfırlama talebiniz alınmıştır. Ancak e-posta gönderilememiştir.",
                        "warning",
                    )
                    return redirect(url_for("kullanici.parolami_unuttum"))
            else:
                flash("Bu e-posta adresi kayıtlı değil.", "danger")
                return redirect(url_for("kullanici.parolami_unuttum"))
    data = {
        "title": "Parolamı Unuttum",
        "form": form,
    }
    return render_template("kullanici/parolami_unuttum.html", **data)


@kullanici.route("/parola-sifirlama-maili-gonderildi")
def parola_sifirlama_maili_gonderildi():
    if current_user.is_authenticated:
        return redirect(url_for("ana.index"))

    data = {
        "title": "Parola Sıfırlama Maili Gönderildi",
    }

    return render_template("kullanici/parola_sifirlama_maili_gonderildi.html", **data)


@kullanici.route("/parola-sifirla/<token>", methods=["GET", "POST"])
def parola_sifirla(token):
    if current_user.is_authenticated:
        return redirect(url_for("ana.index"))

    mt_sql = select(ParolaSifirlamaTokeni).where(ParolaSifirlamaTokeni.token == token)
    mevcut_token = db.session.execute(mt_sql).scalars().first()

    if not mevcut_token:
        flash("Geçersiz veya süresi dolmuş parola sıfırlama talebi.", "danger")
        return redirect(url_for("kullanici.parolami_unuttum"))

    if datetime.now() > mevcut_token.olusturma_ts + timedelta(minutes=30):
        flash(
            "Parola sıfırlama talebinizin süresi dolmuştur. Lütfen tekrar deneyin.",
            "danger",
        )
        db.session.delete(mevcut_token)
        db.session.commit()
        return redirect(url_for("user.parolami_unuttum"))

    form = ParolaSifirlamaFormu()

    if request.method == "POST":
        if form.validate_on_submit():
            yeni_parola = form.parola.data

            k_sql = select(Kullanici).where(Kullanici.id == mevcut_token.kullanici_id)
            kullanici = db.session.execute(k_sql).scalars().first()

            kullanici.parola = bcrypt.generate_password_hash(yeni_parola)
            db.session.commit()

            # Delete the token after successful password reset
            db.session.delete(mevcut_token)
            db.session.commit()

            flash("Parolanız başarıyla değiştirildi. Lütfen giriş yapın.", "success")
            return redirect(url_for("kullanici.giris"))

    data = {
        "title": "Parola Sıfırlama",
        "form": form,
    }
    return render_template("kullanici/parola_sifirla.html", **data)


@kullanici.route("/cikis")
def cikis():
    logout_user()
    return redirect(url_for("kullanici.giris"))


# Profile routes such as profile, change change password, etc.
@kullanici.route("/profil")
@login_required
def profil():
    data = {
        "title": "profil",
        "user": current_user,
        "roles": roles,
    }
    return render_template("user/profil.html", **data)


@kullanici.route("/kullanici-adi-degistir", methods=["GET", "POST"])
@login_required
def kullanici_adi_degistir():
    if current_user.seviye in ["Admin", "Super Admin"]:
        data = {
            "form": KullaniciAdiDegistirmeFormu(),
            "title": "Kullanıcı Adı Değiştir",
        }
        data["form"].ad_soyad.data = current_user.ad_soyad

        if request.method == "POST":
            # get fresh data
            ad_soyad = request.form.get("ad_soyad")
            # update existing data
            current_user.ad_soyad = ad_soyad
            db.session.commit()
            flash("Kullanıcı adınız başarıyla değiştirildi.", "success")
            return redirect(url_for("kullanici.profil"))
        return render_template("kullanici/kullanici_adi_degistir.html", **data)
    else:
        flash("Bu sayfaya erişim izniniz yok.", "danger")
        return redirect(url_for("ana.index"))


@kullanici.route("/change-password", methods=["GET", "POST"])
@login_required
def kullanici_parolasi_degistir():
    data = {
        "form": KullaniciParolasiDegistirmeFormu(),
        "title": "Kullanıcı Parolası Değiştir",
    }
    if request.method == "POST":
        yeni_parola = request.form.get("password")
        parola_tekrari = request.form.get("confirm_password")

        if yeni_parola != parola_tekrari or yeni_parola == "":
            flash("Parolalar eşleşmiyor veya boş bırakılmış.", "danger")
            return redirect(url_for("kullanici.kullanici_parolasi_degistir"))
        current_user.parola = bcrypt.generate_password_hash(yeni_parola)
        db.session.commit()
        flash("Parolanız başarıyla değiştirildi.", "success")
        return redirect(url_for("kullanici.profil"))

    return render_template("kullanici/kullanici_parolasi_degistir.html", **data)
