
import hashlib
from django.urls import reverse
from django.http import HttpResponse,HttpResponseServerError,HttpResponseRedirect,HttpResponseForbidden
from django.core.exceptions import PermissionDenied
from django.contrib import messages
from django.shortcuts import render,redirect
from webapp.views.base import CommonView
from webapp.common import query_00,dump,log_activity
from webapp.models import (koleksi as m_koleksi, master as m_master)

middleware_views_ignored = ['/','login','logout','403','404']
auth_validate_required = ['usr','pwd']

def session(SessionStore,*args,**kwargs):
	for k,v in kwargs.items():
		""" Object of type datetime is not JSON serializable """
		if v.__class__.__name__ == 'datetime': v = str(v);
		SessionStore[k] = v

	sess = {}
	for arg in args: sess[arg] = SessionStore[arg];
	return sess;
# 

def auth_pwd_hash(pwd):
	pwd = hashlib.md5(pwd.encode('utf-8')).hexdigest()
	pwd = hashlib.sha1(pwd.encode('utf-8')).hexdigest()
	return pwd

def auth_account_by(**kwargs):
	account = None
	try:
		user = m_master.Users.objects.filter(**kwargs).select_related().get()
		account = m_master.Users._sanitize_result(user)
		account['role'] = user.pk_roles.role
	except Exception:
		pass

	return account
# 

def validate(SessionStore,*args,**kwargs):
	account = auth_account_by(usr=SessionStore.get('usr'), pwd=SessionStore.get('pwd'))
	if account is None: return False;

	for r in auth_validate_required:
		if SessionStore[r] != account[r]:
			return False

	session(SessionStore, **account)
	return True
# 

def urlpath_validate(path,sess):
	'''
	select access.is
	from access 
	join menus on (menus.pk=access.menus_pk)
	join roles on (roles.pk=access.roles_pk)
	where access.users_pk is null
	and menus.href = '$path'
	and roles.role = '$role'
	'''
	rule_by_role = None
	try:
		rule_by_role = m_master.Access.objects.filter(
			menus_pk__href=path,
			roles_pk__role=sess['role'],
			users_pk=None,
		).get()
	except Exception: pass;
	if rule_by_role and rule_by_role._is: return True;

	with query_00("""
		SELECT access.is,menus.href
		FROM access 
		JOIN menus ON (menus.pk=access.menus_pk)
		JOIN roles ON (roles.pk=access.roles_pk)
		WHERE access.users_pk IS NULL
		and %s like menus.href||'%%'
		and roles.role = %s
		ORDER BY menus.href DESC
		""",[
		path,
		sess['role'],
	]) as q: rule_by_href_part = q.result_one();
	if rule_by_href_part and rule_by_href_part['is']: return True;

	return False
# 

class AuthMiddleware:
	# fn ini hanya jalan sekali, ketika server nyala.
	def __init__(self,get_response):
		self.get_response = get_response

	# Code to be executed for each request before
	# the view (and later middleware) are called.
	# fn ini jalan setiap-sebelum view dijalankan.
	def __call__(self,request):
		request.session['sess_is_auth'] = yn = validate(request.session)
		yn_ignored = any(reverse(i) == request.path for i in middleware_views_ignored)

		if yn is False and yn_ignored == False:
			return HttpResponseRedirect(reverse('login') + '?redirect=' + request.path)

		if yn and yn_ignored == False and urlpath_validate(request.path,request.session) == False:
			raise PermissionDenied

		return self.get_response(request)
	# 
# 

class AuthLoginView(CommonView):
	def get(self, request):
		if validate(request.session): return redirect('/');
		return render(request,'login.html')
	# 

	def post(self, request):
		usr = request.POST.get('usr','');
		pwd = request.POST.get('pwd','');


		if usr == '' or pwd == '':
			messages.warning(request, 'Isian Username atau Password kosong')
			return redirect('login')
		
		account = auth_account_by(usr=usr,pwd=auth_pwd_hash(pwd))
		if account is None:
			messages.error(request, 'User Tidak Ditemukan')
			return redirect('login')

		session(request.session, **account);
						# ✅ Tambahkan catatan login
		log_activity(
			request,
			'login',
			'auth',
			account['pk'],
			f"Login sebagai {account['usr']}"
		)


		if request.GET.get('redirect',None): return HttpResponseRedirect(request.GET['redirect']);
		return redirect('dash')
	# 
# 

class AuthLogoutView(CommonView):
	def get(self, request, *args, **kwargs): return self.logout(request, *args, **kwargs)
	def post(self, request, *args, **kwargs): return self.logout(request, *args, **kwargs)

	def logout(self, request):
		from webapp.common import log_activity

		user_id = request.session.get('pk')
		user_name = request.session.get('usr', 'unknown')
		if user_id:
			log_activity(
				request,
				'logout',
				'auth',
				user_id,
				f"Logout dari sistem ({user_name})"
			)

		request.session.flush()
		return redirect('login')
	# 
# 
