from fastapi import APIRouter, Depends, HTTPException, Query
from typing import List, Optional
import logging
import pydantic

from ..db_engine import db, Manager, Team, Current, model_to_dict, fn
from ..dependencies import oauth2_scheme, valid_token, PRIVATE_IN_SCHEMA, handle_db_errors

logger = logging.getLogger('discord_app')

router = APIRouter(
    prefix='/api/v3/managers',
    tags=['managers']
)


class ManagerModel(pydantic.BaseModel):
    name: str
    image: Optional[str] = None
    headline: Optional[str] = None
    bio: Optional[str] = None


@router.get('')
@handle_db_errors
async def get_managers(
        name: list = Query(default=None), active: Optional[bool] = None, short_output: Optional[bool] = False):
    if active is not None:
        current = Current.latest()
        t_query = Team.select_season(current.season)
        t_query = t_query.where(
            ~(Team.abbrev.endswith('IL')) & ~(Team.abbrev.endswith('MiL'))
        )
        logger.info(f'tquery: {t_query}')
        a_mgr = []
        i_mgr = []

        for x in t_query:
            logger.info(f'Team: {x.abbrev} / mgr1: {x.manager1} / mgr2: {x.manager2}')
            if x.manager1 is not None:
                a_mgr.append(x.manager1)
                logger.info(f'appending {x.manager1.name}')
            if x.manager2 is not None:
                a_mgr.append(x.manager2)
                logger.info(f'appending {x.manager2.name}')

        logger.info(f'a_mgr: {a_mgr}')
        if active:
            final_mgrs = [model_to_dict(y, recurse=not short_output) for y in a_mgr]
        else:
            logger.info(f'checking inactive')
            for z in Manager.select():
                logger.info(f'checking: {z.name}')
                if z not in a_mgr:
                    logger.info(f'+inactive: {z.name}')
                    i_mgr.append(z)
            final_mgrs = [model_to_dict(y, recurse=not short_output) for y in i_mgr]

        return_managers = {
            'count': len(final_mgrs),
            'managers': final_mgrs
        }

    else:
        all_managers = Manager.select()
        if name is not None:
            name_list = [x.lower() for x in name]
            all_managers = all_managers.where(fn.Lower(Manager.name) << name_list)

        return_managers = {
            'count': all_managers.count(),
            'managers': [model_to_dict(x, recurse=not short_output) for x in all_managers]
        }

    db.close()
    return return_managers


@router.get('/{manager_id}')
@handle_db_errors
async def get_one_manager(manager_id: int, short_output: Optional[bool] = False):
    this_manager = Manager.get_or_none(Manager.id == manager_id)
    if this_manager is not None:
        r_manager = model_to_dict(this_manager, recurse=not short_output)
        db.close()
        return r_manager
    else:
        raise HTTPException(status_code=404, detail=f'Manager {manager_id} not found')


@router.patch('/{manager_id}', include_in_schema=PRIVATE_IN_SCHEMA)
@handle_db_errors
async def patch_manager(
        manager_id: int, name: Optional[str] = None, image: Optional[str] = None, headline: Optional[str] = None,
        bio: Optional[str] = None, token: str = Depends(oauth2_scheme)):
    if not valid_token(token):
        logger.warning(f'patch_manager - Bad Token: {token}')
        raise HTTPException(status_code=401, detail='Unauthorized')

    this_manager = Manager.get_or_none(Manager.id == manager_id)
    if this_manager is None:
        db.close()
        raise HTTPException(status_code=404, detail=f'Manager ID {manager_id} not found')

    if name is not None:
        this_manager.name = name
    if image is not None:
        this_manager.image = image
    if headline is not None:
        this_manager.headline = headline
    if bio is not None:
        this_manager.bio = bio

    if this_manager.save() == 1:
        r_manager = model_to_dict(this_manager)
        db.close()
        return r_manager
    else:
        db.close()
        raise HTTPException(status_code=500, detail=f'Unable to patch manager {this_manager}')


@router.post('', include_in_schema=PRIVATE_IN_SCHEMA)
@handle_db_errors
async def post_manager(new_manager: ManagerModel, token: str = Depends(oauth2_scheme)):
    if not valid_token(token):
        logger.warning(f'post_manager - Bad Token: {token}')
        raise HTTPException(status_code=401, detail='Unauthorized')

    this_manager = Manager(**new_manager.dict())

    if this_manager.save():
        r_manager = model_to_dict(this_manager)
        db.close()
        return r_manager
    else:
        db.close()
        raise HTTPException(status_code=500, detail=f'Unable to post manager {this_manager.name}')


@router.delete('/{manager_id}', include_in_schema=PRIVATE_IN_SCHEMA)
@handle_db_errors
async def delete_manager(manager_id: int, token: str = Depends(oauth2_scheme)):
    if not valid_token(token):
        logger.warning(f'delete_manager - Bad Token: {token}')
        raise HTTPException(status_code=401, detail='Unauthorized')

    this_manager = Manager.get_or_none(Manager.id == manager_id)
    if this_manager is None:
        db.close()
        raise HTTPException(status_code=404, detail=f'Manager ID {manager_id} not found')

    count = this_manager.delete_instance()
    db.close()

    if count == 1:
        return f'Manager {manager_id} has been deleted'
    else:
        raise HTTPException(status_code=500, detail=f'Manager {manager_id} could not be deleted')
