import logging
from typing import Dict, Optional

from fastapi import APIRouter, Request, Form, HTTPException
from fastapi.responses import RedirectResponse
from itsdangerous import URLSafeSerializer, BadSignature

from app.config import get_settings
from app.student_api import fetch_student_by_credentials

logger = logging.getLogger(__name__)

router = APIRouter(prefix="", tags=["auth"])

COOKIE_NAME = "session"

#
# Local fallback login mapping for demo mode.
# Replace or remove this once Student API or SSO integration is available.
#
# To test with a real name format add entries like:
#   "1234561": "student"   # Student_ID from the API
ALLOWED_LOCAL: Dict[str, str] = {
	"student": "student",
	"advisor": "advisor",
	"financial-aid": "financial-aid",
	"counselor": "counselor",
}

# Role detection
# When the Student API is live, all logged-in users from that API are "student".
# Staff roles (advisor, financial-aid, counselor) still use local fallback
# until a separate Staff API is available.
# Staff API lookup should replace this fallback once it is ready.
STAFF_IDS: Dict[str, str] = {
	"advisor": "advisor",
	"financial-aid": "financial-aid",
	"counselor": "counselor",
}


def _serializer() -> URLSafeSerializer:
	return URLSafeSerializer(get_settings().secret_key, salt="session")


def _set_session(resp: RedirectResponse, payload: Dict) -> RedirectResponse:
	# single place that signs the payload and sets the session cookie
	# cookie is restricted to https automatically when not in debug mode
	token = _serializer().dumps(payload)
	resp.set_cookie(
		COOKIE_NAME, token,
		httponly=True,
		samesite="lax",
		secure=get_settings().is_production,
	)
	return resp


@router.post("/login")
async def login(
	username: str = Form(...),
	password: str = Form(...),
	email:	str = Form(default=""),
):

	# step 1: staff roles bypass the student api
	if username in STAFF_IDS:
		role = STAFF_IDS[username]
		resp = RedirectResponse(url=f"{role}/dashboard", status_code=302)
		_set_session(resp, {
			"username":   username,
			"role":	   role,
			"first_name": username.replace("-", " ").replace("_", " ").title(),
			"last_name":  "",
			"student_id": "",
			"email":	  "",
			# profile fields empty for staff - extend when staff api is ready
			"enrollment_status": "",
			"program_id":		"",
			"admit_term":		"",
			"student_type":	  "",
			"academic_level":	"",
		})
		logger.info("Staff login succeeded for role=%s", role)
		return resp

	# step 2: try real student api
	# ensure STUDENT_API_URL and STUDENT_API_TOKEN are configured in .env for live student login
	profile = await fetch_student_by_credentials(
		student_id=username,
		email=email,
		password=password,
	)

	if profile:
		# api login succeeded
		resp = RedirectResponse(url="student/dashboard", status_code=302)
		_set_session(resp, {
			"username":		  profile.student_id or username,
			"role":			  "student",
			"first_name":		profile.first_name,
			"last_name":		 profile.last_name,
			"student_id":		profile.student_id,
			"email":			 profile.email,
			"enrollment_status": profile.enrollment_status,
			"program_id":		profile.program_id,
			"admit_term":		profile.admit_term,
			"student_type":	  profile.student_type,
			"academic_level":	profile.academic_level,
		})
		logger.info("Student API login succeeded for student_id=%s", profile.student_id)
		return resp

	# step 3: fall back to local allowed dict (demo mode)
	if username in ALLOWED_LOCAL:
		role = ALLOWED_LOCAL[username]
		resp = RedirectResponse(url=f"{role}/dashboard", status_code=302)
		_set_session(resp, {
			"username":		  username,
			"role":			  role,
			"first_name":		username.replace("-", " ").replace("_", " ").title(),
			"last_name":		 "",
			"student_id":		username,
			"email":			 "",
			"enrollment_status": "",
			"program_id":		"",
			"admit_term":		"",
			"student_type":	  "",
			"academic_level":	"",
		})
		logger.info("Local fallback login succeeded for role=%s", role)
		return resp

	# step 4: all methods failed, back to login
	logger.warning("Login failed for username=%s", username)
	return RedirectResponse(url="login-page", status_code=302)


@router.get("/logout")
async def logout():
	resp = RedirectResponse(url="login-page", status_code=302)
	resp.delete_cookie(COOKIE_NAME)
	return resp


def get_current_user(request: Request) -> Dict[str, Optional[str]]:
	"""
	FastAPI dependency: reads the signed session cookie and returns the
	full user dict including first_name, last_name, student_id, etc.
	Raises 401 if the cookie is missing or tampered with.
	"""
	token = request.cookies.get(COOKIE_NAME)
	if not token:
		raise HTTPException(status_code=401, detail="Not authenticated")
	try:
		data = _serializer().loads(token)
		return {
			"username":		  data.get("username"),
			"role":			  data.get("role"),
			"first_name":		data.get("first_name", ""),
			"last_name":		 data.get("last_name", ""),
			"student_id":		data.get("student_id", ""),
			"email":			 data.get("email", ""),
			"enrollment_status": data.get("enrollment_status", ""),
			"program_id":		data.get("program_id", ""),
			"admit_term":		data.get("admit_term", ""),
			"student_type":	  data.get("student_type", ""),
			"academic_level":	data.get("academic_level", ""),
		}
	except BadSignature:
		raise HTTPException(status_code=401, detail="Invalid or expired session")