import hashlib
import secrets
import logging
from datetime import datetime, timedelta, timezone
from fastapi import APIRouter, Request
from fastapi.responses import RedirectResponse, HTMLResponse
from devplacepy.database import get_table
from devplacepy.templating import templates
from devplacepy.utils import hash_password, verify_password, create_session, generate_uid, get_current_user
from devplacepy.seo import base_seo_context

logger = logging.getLogger(__name__)
router = APIRouter()


@router.get("/signup", response_class=HTMLResponse)
async def signup_page(request: Request):
    user = get_current_user(request)
    if user:
        return RedirectResponse(url="/feed", status_code=302)
    seo_ctx = base_seo_context(
        request,
        title="Join DevPlace",
        description="Create your DevPlace account and start connecting with developers.",
        robots="noindex,nofollow",
    )
    return templates.TemplateResponse(request, "signup.html", {**seo_ctx, "request": request})


@router.get("/login", response_class=HTMLResponse)
async def login_page(request: Request):
    user = get_current_user(request)
    if user:
        return RedirectResponse(url="/feed", status_code=302)
    seo_ctx = base_seo_context(
        request,
        title="Sign In",
        description="Sign in to DevPlace to connect with developers.",
        robots="noindex,nofollow",
    )
    return templates.TemplateResponse(request, "login.html", {**seo_ctx, "request": request})


@router.post("/signup")
async def signup(request: Request):
    form = await request.form()
    username = form.get("username", "").strip()
    email = form.get("email", "").strip().lower()
    password = form.get("password", "")
    confirm_password = form.get("confirm_password", "")

    errors = []
    if len(username) < 3 or len(username) > 32:
        errors.append("Username must be between 3 and 32 characters")
    if not username.isascii() or not all(c.isalnum() or c in ("-", "_") for c in username):
        errors.append("Username can only contain letters, numbers, hyphens, and underscores")
    if not email or "@" not in email or len(email) > 255:
        errors.append("Valid email is required")
    if len(password) < 6:
        errors.append("Password must be at least 6 characters")
    if password != confirm_password:
        errors.append("Passwords do not match")

    users = get_table("users")
    if users.find_one(username=username):
        errors.append("Username already taken")
    if users.find_one(email=email):
        errors.append("Email already registered")

    if errors:
        seo_ctx = base_seo_context(request, title="Join DevPlace", robots="noindex,nofollow")
        return templates.TemplateResponse(
            request, "signup.html",
            {**seo_ctx, "request": request, "errors": errors, "username": username, "email": email},
        )

    uid = generate_uid()
    is_first = len(list(users.all())) == 0
    users.insert({
        "uid": uid,
        "username": username,
        "email": email,
        "password_hash": hash_password(password),
        "bio": "",
        "location": "",
        "git_link": "",
        "website": "",
        "role": "Admin" if is_first else "Member",
        "is_active": True,
        "level": 1,
        "xp": 0,
        "stars": 0,
        "created_at": datetime.now(timezone.utc).isoformat(),
    })

    badges = get_table("badges")
    badges.insert({
        "uid": generate_uid(),
        "user_uid": uid,
        "badge_name": "Member",
        "created_at": datetime.now(timezone.utc).isoformat(),
    })

    token = create_session(uid)
    response = RedirectResponse(url="/feed", status_code=302)
    response.set_cookie(key="session", value=token, max_age=86400 * 7, httponly=True, samesite="lax")
    logger.info(f"User {username} signed up")
    return response


@router.post("/login")
async def login(request: Request):
    form = await request.form()
    email = form.get("email", "").strip().lower()
    password = form.get("password", "")
    remember_me = form.get("remember_me") == "on"

    errors = []
    if not email or not password:
        errors.append("Email and password are required")

    users = get_table("users")
    user = users.find_one(email=email) if not errors else None

    if not user or not verify_password(password, user["password_hash"]):
        errors.append("Invalid email or password")

    if errors:
        seo_ctx = base_seo_context(request, title="Sign In", robots="noindex,nofollow")
        return templates.TemplateResponse(
            request, "login.html",
            {**seo_ctx, "request": request, "errors": errors, "email": email},
        )

    token = create_session(user["uid"])
    max_age = 86400 * 30 if remember_me else 86400 * 7
    response = RedirectResponse(url="/feed", status_code=302)
    response.set_cookie(key="session", value=token, max_age=max_age, httponly=True, samesite="lax")
    logger.info(f"User {user['username']} logged in")
    return response


@router.get("/forgot-password", response_class=HTMLResponse)
async def forgot_password_page(request: Request):
    seo_ctx = base_seo_context(
        request,
        title="Reset Password",
        robots="noindex,nofollow",
    )
    return templates.TemplateResponse(request, "forgot_password.html", {**seo_ctx, "request": request})


@router.post("/forgot-password")
async def forgot_password(request: Request):
    form = await request.form()
    email = form.get("email", "").strip().lower()
    errors = []
    if not email or "@" not in email:
        errors.append("Valid email is required")

    seo_ctx = base_seo_context(request, title="Reset Password", robots="noindex,nofollow")
    if errors:
        return templates.TemplateResponse(request, "forgot_password.html", {
            **seo_ctx, "request": request, "errors": errors,
        })

    users = get_table("users")
    user = users.find_one(email=email)
    if user:
        token = secrets.token_hex(32)
        token_hash = hashlib.sha256(token.encode()).hexdigest()
        resets = get_table("password_resets")
        resets.insert({
            "uid": generate_uid(),
            "user_uid": user["uid"],
            "token": token_hash,
            "expires_at": (datetime.now(timezone.utc) + timedelta(hours=1)).isoformat(),
            "used": False,
            "created_at": datetime.now(timezone.utc).isoformat(),
        })
        logger.info(f"Password reset requested for {email}")

    return templates.TemplateResponse(request, "forgot_password.html", {
        **seo_ctx, "request": request, "sent": True,
    })


@router.get("/reset-password/{token}", response_class=HTMLResponse)
async def reset_password_page(request: Request, token: str):
    seo_ctx = base_seo_context(
        request,
        title="Set New Password",
        robots="noindex,nofollow",
    )
    return templates.TemplateResponse(request, "reset_password.html", {
        **seo_ctx, "request": request, "token": token,
    })


@router.post("/reset-password/{token}")
async def reset_password(request: Request, token: str):
    form = await request.form()
    password = form.get("password", "")
    confirm = form.get("confirm_password", "")

    errors = []
    if len(password) < 6:
        errors.append("Password must be at least 6 characters")
    if password != confirm:
        errors.append("Passwords do not match")

    if errors:
        seo_ctx = base_seo_context(request, title="Set New Password", robots="noindex,nofollow")
        return templates.TemplateResponse(request, "reset_password.html", {
            **seo_ctx, "request": request, "token": token, "errors": errors,
        })

    resets = get_table("password_resets")
    users = get_table("users")
    token_hash = hashlib.sha256(token.encode()).hexdigest()
    matched = resets.find_one(token=token_hash, used=False)

    if not matched:
        errors.append("Invalid or expired reset token")
        return templates.TemplateResponse(request, "reset_password.html", {
            "request": request, "token": token, "errors": errors,
        })
    expires = datetime.fromisoformat(matched["expires_at"])
    if expires.tzinfo is None:
        expires = expires.replace(tzinfo=timezone.utc)
    if expires < datetime.now(timezone.utc):
        errors.append("Invalid or expired reset token")
        return templates.TemplateResponse(request, "reset_password.html", {
            "request": request, "token": token, "errors": errors,
        })

    users.update({"uid": matched["user_uid"], "password_hash": hash_password(password)}, ["uid"])
    resets.update({"id": matched["id"], "used": True}, ["id"])
    logger.info(f"Password reset completed for user {matched['user_uid']}")
    return RedirectResponse(url="/auth/login", status_code=302)


@router.get("/logout")
async def logout(request: Request):
    token = request.cookies.get("session")
    if token:
        sessions = get_table("sessions")
        session = sessions.find_one(session_token=token)
        if session:
            sessions.delete(id=session["id"])
    response = RedirectResponse(url="/", status_code=302)
    response.delete_cookie("session")
    return response
