import asyncio
from contextlib import asynccontextmanager

from authx import AuthXConfig, AuthX, RequestToken
from fastapi import Response, FastAPI, Request, HTTPException, Depends
from fastapi.responses import RedirectResponse
import uvicorn

from src.database.db import Database
from src.database.user import User, UserLogin

### Settings
# TODO: Create .env

PORT = 7535
ADMIN_NAME = 'admin'
ADMIN_PASSWORD = 'admin'
DATABASE_USER = 'ADMIN'
DATABASE_PASS = '123123'
DATABASE_HOST = '127.0.0.1'
DATABASE_NAME = 'sonoma-db'
SECRET = 'SECRET'

###

@asynccontextmanager
async def lifespan(app: FastAPI):
    await db.connect()
    await db.init()
    yield
    await db.disconnect()

db = Database(
    ADMIN_NAME,
    ADMIN_PASSWORD,
    DATABASE_USER,
    DATABASE_PASS,
    DATABASE_HOST,
    DATABASE_NAME
)

app = FastAPI(title='sclient-main-server', lifespan=lifespan)

config = AuthXConfig()
config.JWT_SECRET_KEY = SECRET
config.JWT_ACCESS_COOKIE_NAME = "sclient_access_token"
config.JWT_TOKEN_LOCATION = ["cookies"]

security = AuthX(config=config)
security.handle_errors(app)


class App:

    @app.get('/')
    async def docs(self: Request):
        return RedirectResponse(f'{self.url}docs')

    ### Auth

    @app.post('/login')
    async def login(self: Request, credentials: UserLogin, response: Response):
        user = await db.get_user(credentials.username)

        if user is not None:
            if user[1] == credentials.password:
                token = security.create_access_token(uid=credentials.username)
                response.set_cookie(config.JWT_ACCESS_COOKIE_NAME, token)
                return {
                    "access_token": token
                }
        raise HTTPException(
            401,
            detail='Incorrect username or password'
        )
    ###

    ### Protected

    @app.get('/protected/auth', dependencies=[Depends(security.access_token_required)])
    async def auth(self: Request):
        try:
            return {"message": "Hello world !"}
        except Exception as e:
            raise HTTPException(
                401,
                detail={"message": str(e)}
            ) from e

    ###


def main():
    uvicorn.run(app, host='0.0.0.0', port=PORT)

if __name__ == '__main__':
    main()