from fastapi import APIRouter, Depends, Request, Response
from pydantic import BaseModel
from sqlalchemy.orm import Session

from flyway.api.deps import SESSION_COOKIE, current_actor, get_db, set_session_cookie
from flyway.auth.service import actor_for, authenticate, change_password, create_session, delete_session
from flyway.domain.actor import Actor
from flyway.domain.clock import utcnow
from flyway.models import AppUser

public = APIRouter(prefix="/api/auth")
protected = APIRouter(prefix="/api/auth")


class LoginIn(BaseModel):
    username: str
    password: str
    remember_me: bool = False


class PasswordIn(BaseModel):
    current_password: str
    new_password: str


def _me(actor: Actor, csrf: str) -> dict:
    return {"username": actor.username, "full_name": actor.full_name, "is_admin": actor.is_admin, "csrf_token": csrf}


@public.post("/login")
def login(body: LoginIn, response: Response, db: Session = Depends(get_db)):
    now = utcnow()
    try:
        user = authenticate(db, body.username, body.password, now)
    finally:
        db.commit()  # 失败计数也要保存
    token, csrf = create_session(db, user, now, persistent=body.remember_me)
    db.commit()
    set_session_cookie(response, token, body.remember_me)
    return _me(actor_for(user), csrf)


@protected.get("/me")
def me(request: Request, actor: Actor = Depends(current_actor)):
    return _me(actor, request.state.csrf_token)


@protected.post("/logout", status_code=204)
def logout(request: Request, response: Response, db: Session = Depends(get_db), _: Actor = Depends(current_actor)):
    delete_session(db, request.cookies.get(SESSION_COOKIE))
    db.commit()
    response.delete_cookie(SESSION_COOKIE)


@protected.post("/password", status_code=204)
def password(body: PasswordIn, db: Session = Depends(get_db), actor: Actor = Depends(current_actor)):
    change_password(db, db.get(AppUser, actor.user_id), body.current_password, body.new_password)
    db.commit()
