"""Panel akun: admin membuat dosen, mengatur kelas dan akses.

Semua rute di sini butuh login. Pembuatan dosen, reset sandi, dan nonaktifkan
akun hanya untuk admin; dosen hanya boleh melihat mahasiswa di kelasnya dan
membuat kelas sendiri.
"""

from __future__ import annotations

import secrets
import string

from flask import Blueprint, abort, flash, redirect, render_template, request, url_for

from keamanan import POLA_PENGGUNA, butuh, hash_sandi, pengguna_sekarang

bp = Blueprint("akun", __name__, url_prefix="/admin")

MIN_SANDI = 8
ABJAD_KODE = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"


def _kode_baru() -> str:
    from app import kueri
    for _ in range(20):
        kode = "".join(secrets.choice(ABJAD_KODE) for _ in range(6))
        if not kueri("SELECT 1 AS a FROM kelas WHERE kode_gabung = %s", (kode,), satu=True):
            return kode
    raise RuntimeError("Tidak bisa membuat kode kelas unik.")


@bp.get("/pengguna")
@butuh("admin", "dosen")
def pengguna():
    from app import kueri
    saya = pengguna_sekarang()
    if saya["peran"] == "admin":
        dosen = kueri("SELECT * FROM pengguna WHERE peran='dosen' ORDER BY nama")
        mahasiswa = kueri("SELECT * FROM pengguna WHERE peran='mahasiswa' ORDER BY nama")
    else:
        dosen = []
        mahasiswa = kueri(
            "SELECT DISTINCT p.* FROM pengguna p "
            "JOIN kelas_anggota ka ON ka.pengguna_id = p.id "
            "JOIN kelas k ON k.id = ka.kelas_id WHERE k.dosen_id = %s ORDER BY p.nama",
            (saya["id"],))
    kelas_saya = kueri(
        "SELECT k.*, (SELECT COUNT(*) FROM kelas_anggota ka WHERE ka.kelas_id = k.id) anggota "
        "FROM kelas k WHERE %s = 'admin' OR k.dosen_id = %s ORDER BY k.nama",
        (saya["peran"], saya["id"]))
    return render_template("admin_pengguna.html", dosen=dosen, mahasiswa=mahasiswa,
                           kelas=kelas_saya, sandi_baru=request.args.get("sandi"))


@bp.post("/pengguna/dosen")
@butuh("admin")
def buat_dosen():
    from app import kueri
    nama = (request.form.get("nama") or "").strip()
    username = (request.form.get("pengguna") or "").strip()
    sandi = (request.form.get("sandi") or "").strip()
    email = (request.form.get("email") or "").strip() or None
    galat = []
    if not nama:
        galat.append("Nama dosen wajib diisi.")
    if not POLA_PENGGUNA.match(username):
        galat.append("Nama pengguna 3–40 karakter: huruf, angka, titik, garis bawah.")
    if len(sandi) < MIN_SANDI:
        galat.append(f"Sandi awal minimal {MIN_SANDI} karakter.")
    if kueri("SELECT id FROM pengguna WHERE pengguna=%s", (username,), satu=True):
        galat.append("Nama pengguna sudah dipakai.")
    if galat:
        for pesan in galat:
            flash(pesan, "galat")
    else:
        kueri("INSERT INTO pengguna (nama, pengguna, email, sandi_hash, peran, aktif, ganti_sandi) "
              "VALUES (%s, %s, %s, %s, 'dosen', 1, 1)",
              (nama, username, email, hash_sandi(sandi)))
        flash(f"Akun dosen “{nama}” dibuat. Dosen wajib ganti sandi saat masuk pertama.", "ok")
    return redirect(url_for("akun.pengguna"))


@bp.post("/pengguna/<int:pid>/aktif")
@butuh("admin", "dosen")
def atur_aktif(pid: int):
    from app import kueri
    saya = pengguna_sekarang()
    target = kueri("SELECT * FROM pengguna WHERE id=%s", (pid,), satu=True)
    if not target:
        abort(404)
    if saya["peran"] != "admin":
        # dosen hanya boleh menonaktifkan mahasiswa di kelasnya
        if target["peran"] != "mahasiswa" or not kueri(
                "SELECT 1 AS a FROM kelas_anggota ka JOIN kelas k ON k.id = ka.kelas_id "
                "WHERE ka.pengguna_id=%s AND k.dosen_id=%s", (pid, saya["id"]), satu=True):
            abort(404)
    baru = 0 if target["aktif"] else 1
    kueri("UPDATE pengguna SET aktif=%s WHERE id=%s", (baru, pid))
    flash(f"Akun {target['nama']} {'diaktifkan' if baru else 'dinonaktifkan'}.", "ok")
    return redirect(url_for("akun.pengguna"))


@bp.post("/pengguna/<int:pid>/reset")
@butuh("admin", "dosen")
def reset_sandi(pid: int):
    from app import kueri
    saya = pengguna_sekarang()
    target = kueri("SELECT * FROM pengguna WHERE id=%s", (pid,), satu=True)
    if not target:
        abort(404)
    if saya["peran"] != "admin":
        if target["peran"] != "mahasiswa" or not kueri(
                "SELECT 1 AS a FROM kelas_anggota ka JOIN kelas k ON k.id = ka.kelas_id "
                "WHERE ka.pengguna_id=%s AND k.dosen_id=%s", (pid, saya["id"]), satu=True):
            abort(404)
    sandi = "".join(secrets.choice(string.ascii_lowercase + string.digits) for _ in range(10))
    kueri("UPDATE pengguna SET sandi_hash=%s, ganti_sandi=1 WHERE id=%s",
          (hash_sandi(sandi), pid))
    flash(f"Sandi sementara untuk {target['nama']}: {sandi} — catat sekarang, tidak ditampilkan lagi.",
          "ok")
    return redirect(url_for("akun.pengguna"))


@bp.post("/kelas")
@butuh("admin", "dosen")
def buat_kelas():
    from app import kueri
    saya = pengguna_sekarang()
    nama = (request.form.get("nama") or "").strip()
    if not nama:
        flash("Nama kelas wajib diisi.", "galat")
        return redirect(url_for("akun.pengguna"))
    kode = _kode_baru()
    kueri("INSERT INTO kelas (nama, kode_gabung, dosen_id, deskripsi) VALUES (%s, %s, %s, %s)",
          (nama, kode, saya["id"], (request.form.get("deskripsi") or "").strip()))
    flash(f"Kelas “{nama}” dibuat. Kode gabung: {kode}", "ok")
    return redirect(url_for("akun.pengguna"))
