"""
Api Key validation
"""
from typing import Optional

from fastapi.security.api_key import APIKeyHeader
from fastapi import HTTPException, Security, Depends
from starlette.status import HTTP_401_UNAUTHORIZED, HTTP_400_BAD_REQUEST, HTTP_403_FORBIDDEN

from server.core.security import verify_key
from server.db.mongodb import AsyncIOMotorClient, get_database
from server.models.user import User
from server.db.crud.user import get_user_by_email
from pydantic import EmailStr


api_key_scheme = APIKeyHeader(name="X-API-KEY", auto_error=False)
email_scheme = APIKeyHeader(name="X-EMAIL-ID", auto_error=False)


async def validate_request(
        api_key: Optional[str] = Security(api_key_scheme),
        email_id: Optional[EmailStr] = Security(email_scheme),
        db: AsyncIOMotorClient = Depends(get_database)
) -> Optional[User]:
    """Validate a request with given email and api key
    to any endpoint resource
    """
    if api_key is None:
        raise HTTPException(
            status_code=HTTP_400_BAD_REQUEST, detail="X-API-KEY is missing", headers={}
        )
    if email_id is None:
        raise HTTPException(
            status_code=HTTP_400_BAD_REQUEST, detail="X-EMAIL-ID is missing", headers={}
        )

    user = await get_user_by_email(db, email_id)

    # verify email & API key
    if user:
        api_key = str(user.salt) + str(api_key)

        if not verify_key(api_key, user.hashed_api_key):
            # api key mismatch
            raise HTTPException(
                status_code=HTTP_401_UNAUTHORIZED, detail="Access not allowed", headers={}
            )
        if user.disabled:
            # disabled user
            raise HTTPException(
                status_code=HTTP_403_FORBIDDEN, detail="User is disabled", headers={}
            )
        if not user.is_active:
            # user's email is not verified
            raise HTTPException(
                status_code=HTTP_401_UNAUTHORIZED, detail="Email not verified", headers={}
            )

        # All verified
        return User(**user.dict())
    else:
        # not a valid email provided
        raise HTTPException(
            status_code=HTTP_400_BAD_REQUEST, detail="Unknown Email", headers={}
        )

[((495, 543), 'fastapi.security.api_key.APIKeyHeader', 'APIKeyHeader', ([], {'name': '"""X-API-KEY"""', 'auto_error': '(False)'}), "(name='X-API-KEY', auto_error=False)\n", (507, 543), False, 'from fastapi.security.api_key import APIKeyHeader\n'), ((559, 608), 'fastapi.security.api_key.APIKeyHeader', 'APIKeyHeader', ([], {'name': '"""X-EMAIL-ID"""', 'auto_error': '(False)'}), "(name='X-EMAIL-ID', auto_error=False)\n", (571, 608), False, 'from fastapi.security.api_key import APIKeyHeader\n'), ((672, 696), 'fastapi.Security', 'Security', (['api_key_scheme'], {}), '(api_key_scheme)\n', (680, 696), False, 'from fastapi import HTTPException, Security, Depends\n'), ((737, 759), 'fastapi.Security', 'Security', (['email_scheme'], {}), '(email_scheme)\n', (745, 759), False, 'from fastapi import HTTPException, Security, Depends\n'), ((794, 815), 'fastapi.Depends', 'Depends', (['get_database'], {}), '(get_database)\n', (801, 815), False, 'from fastapi import HTTPException, Security, Depends\n'), ((967, 1062), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': 'HTTP_400_BAD_REQUEST', 'detail': '"""X-API-KEY is missing"""', 'headers': '{}'}), "(status_code=HTTP_400_BAD_REQUEST, detail=\n    'X-API-KEY is missing', headers={})\n", (980, 1062), False, 'from fastapi import HTTPException, Security, Depends\n'), ((1119, 1215), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': 'HTTP_400_BAD_REQUEST', 'detail': '"""X-EMAIL-ID is missing"""', 'headers': '{}'}), "(status_code=HTTP_400_BAD_REQUEST, detail=\n    'X-EMAIL-ID is missing', headers={})\n", (1132, 1215), False, 'from fastapi import HTTPException, Security, Depends\n'), ((1251, 1282), 'server.db.crud.user.get_user_by_email', 'get_user_by_email', (['db', 'email_id'], {}), '(db, email_id)\n', (1268, 1282), False, 'from server.db.crud.user import get_user_by_email\n'), ((2120, 2207), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': 'HTTP_400_BAD_REQUEST', 'detail': '"""Unknown Email"""', 'headers': '{}'}), "(status_code=HTTP_400_BAD_REQUEST, detail='Unknown Email',\n    headers={})\n", (2133, 2207), False, 'from fastapi import HTTPException, Security, Depends\n'), ((1390, 1430), 'server.core.security.verify_key', 'verify_key', (['api_key', 'user.hashed_api_key'], {}), '(api_key, user.hashed_api_key)\n', (1400, 1430), False, 'from server.core.security import verify_key\n'), ((1481, 1575), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': 'HTTP_401_UNAUTHORIZED', 'detail': '"""Access not allowed"""', 'headers': '{}'}), "(status_code=HTTP_401_UNAUTHORIZED, detail=\n    'Access not allowed', headers={})\n", (1494, 1575), False, 'from fastapi import HTTPException, Security, Depends\n'), ((1673, 1761), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': 'HTTP_403_FORBIDDEN', 'detail': '"""User is disabled"""', 'headers': '{}'}), "(status_code=HTTP_403_FORBIDDEN, detail='User is disabled',\n    headers={})\n", (1686, 1761), False, 'from fastapi import HTTPException, Security, Depends\n'), ((1880, 1974), 'fastapi.HTTPException', 'HTTPException', ([], {'status_code': 'HTTP_401_UNAUTHORIZED', 'detail': '"""Email not verified"""', 'headers': '{}'}), "(status_code=HTTP_401_UNAUTHORIZED, detail=\n    'Email not verified', headers={})\n", (1893, 1974), False, 'from fastapi import HTTPException, Security, Depends\n')]