"""
Authentication routes for StarPunk

Handles IndieLogin authentication flow including login form, OAuth callback,
logout functionality, and IndieAuth endpoints for Micropub clients.
"""

from flask import (
    Blueprint,
    current_app,
    flash,
    jsonify,
    redirect,
    render_template,
    request,
    session,
    url_for,
)

from starpunk.auth import (
    IndieLoginError,
    InvalidStateError,
    UnauthorizedError,
    destroy_session,
    handle_callback,
    initiate_login,
    require_auth,
    verify_session,
)

# Create blueprint
bp = Blueprint("auth", __name__, url_prefix="/auth")


@bp.route("/login", methods=["GET"])
def login_form():
    """
    Display login form

    If user is already authenticated, redirects to admin dashboard.
    Otherwise shows login form for IndieLogin authentication.

    Returns:
        Redirect to dashboard if authenticated, otherwise login template

    Template: templates/admin/login.html
    """
    # Check if already logged in
    session_token = request.cookies.get("starpunk_session")
    if session_token and verify_session(session_token):
        return redirect(url_for("admin.dashboard"))

    return render_template("admin/login.html")


@bp.route("/login", methods=["POST"])
def login_initiate():
    """
    Initiate IndieLogin authentication flow

    Validates the submitted 'me' URL and redirects to IndieLogin.com
    for authentication.

    Form data:
        me: User's personal website URL

    Returns:
        Redirect to IndieLogin.com or back to login form on error

    Raises:
        Flashes error message and redirects on validation failure
    """
    me_url = request.form.get("me", "").strip()

    if not me_url:
        flash("Please enter your website URL", "error")
        return redirect(url_for("auth.login_form"))

    try:
        # Initiate IndieLogin flow
        auth_url = initiate_login(me_url)
        return redirect(auth_url)
    except ValueError as e:
        flash(str(e), "error")
        return redirect(url_for("auth.login_form"))


@bp.route("/callback")
def callback():
    """
    Handle IndieLogin callback

    Processes the OAuth callback from IndieLogin.com, validates the
    authorization code, state token, and issuer, then creates an
    authenticated session using PKCE verification.

    Query parameters:
        code: Authorization code from IndieLogin
        state: CSRF state token
        iss: Issuer identifier (should be https://indielogin.com/)

    Returns:
        Redirect to admin dashboard on success, login form on failure

    Sets:
        session cookie (HttpOnly, Secure, SameSite=Lax, 30 day expiry)
    """
    code = request.args.get("code")
    state = request.args.get("state")
    iss = request.args.get("iss")  # Extract issuer parameter

    if not code or not state:
        flash("Missing authentication parameters", "error")
        return redirect(url_for("auth.login_form"))

    try:
        # Handle callback and create session with PKCE verification
        session_token = handle_callback(code, state, iss)  # Pass issuer

        # Create response with redirect
        response = redirect(url_for("admin.dashboard"))

        # Set secure session cookie
        secure = current_app.config.get("SITE_URL", "").startswith("https://")
        response.set_cookie(
            "starpunk_session",
            session_token,
            httponly=True,
            secure=secure,
            samesite="Lax",
            max_age=30 * 24 * 60 * 60,  # 30 days
        )

        flash("Login successful!", "success")
        return response

    except InvalidStateError as e:
        current_app.logger.error(f"Invalid state error: {e}")
        flash("Authentication failed: Invalid state token (possible CSRF)", "error")
        return redirect(url_for("auth.login_form"))

    except UnauthorizedError as e:
        current_app.logger.error(f"Unauthorized: {e}")
        flash("Authentication failed: Not authorized as admin", "error")
        return redirect(url_for("auth.login_form"))

    except IndieLoginError as e:
        current_app.logger.error(f"IndieLogin error: {e}")
        flash(f"Authentication failed: {e}", "error")
        return redirect(url_for("auth.login_form"))

    except Exception as e:
        current_app.logger.error(f"Unexpected auth error: {e}")
        flash("Authentication failed: An unexpected error occurred", "error")
        return redirect(url_for("auth.login_form"))


@bp.route("/logout", methods=["POST"])
@require_auth
def logout():
    """
    Logout and destroy session

    Destroys the user's session and clears the session cookie.
    Requires authentication (user must be logged in to logout).

    Returns:
        Redirect to homepage with session cookie cleared

    Decorator: @require_auth
    """
    session_token = request.cookies.get("starpunk_session")

    # Destroy session in database
    if session_token:
        try:
            destroy_session(session_token)
        except Exception as e:
            current_app.logger.error(f"Error destroying session: {e}")

    # Clear cookie and redirect
    response = redirect(url_for("public.index"))
    response.delete_cookie("starpunk_session")

    flash("Logged out successfully", "success")
    return response


