from typing import Optional

from chalicelib.core import roles, traces, assist_records
from chalicelib.core.sessions import sessions
from chalicelib.core import assist_stats
from chalicelib.core import unlock, signals
from chalicelib.utils import assist_helper

unlock.check()

from or_dependencies import OR_context, OR_role
from routers.base import get_routers
import schemas
from fastapi import Depends, Body, Query

public_app, app, app_apikey = get_routers()


@app.get('/client/roles', tags=["client", "roles"], dependencies=[OR_role("owner", "admin")])
def get_roles(context: schemas.CurrentContext = Depends(OR_context)):
    return {
        'data': roles.get_roles(tenant_id=context.tenant_id)
    }


@app.post('/client/roles', tags=["client", "roles"], dependencies=[OR_role("owner", "admin")])
@app.put('/client/roles', tags=["client", "roles"], dependencies=[OR_role("owner", "admin")])
def add_role(data: schemas.RolePayloadSchema = Body(...),
             context: schemas.CurrentContext = Depends(OR_context)):
    data = roles.create(tenant_id=context.tenant_id, user_id=context.user_id, data=data)
    if "errors" in data:
        return data

    return {
        'data': data
    }


@app.post('/client/roles/{roleId}', tags=["client", "roles"], dependencies=[OR_role("owner", "admin")])
@app.put('/client/roles/{roleId}', tags=["client", "roles"], dependencies=[OR_role("owner", "admin")])
def edit_role(roleId: int, data: schemas.RolePayloadSchema = Body(...),
              context: schemas.CurrentContext = Depends(OR_context)):
    data = roles.update(tenant_id=context.tenant_id, user_id=context.user_id, role_id=roleId, data=data)
    if "errors" in data:
        return data

    return {
        'data': data
    }


@app.delete('/client/roles/{roleId}', tags=["client", "roles"], dependencies=[OR_role("owner", "admin")])
def delete_role(roleId: int, _=Body(None), context: schemas.CurrentContext = Depends(OR_context)):
    data = roles.delete(tenant_id=context.tenant_id, user_id=context.user_id, role_id=roleId)
    if "errors" in data:
        return data
    return {
        'data': data
    }


@app.get('/config/assist/credentials', tags=["assist"])
@app.get('/assist/credentials', tags=["assist"])
def get_assist_credentials():
    return {"data": assist_helper.get_full_config()}


@app.post('/trails', tags=["traces", "trails"], dependencies=[OR_role("owner", "admin")])
def get_trails(data: schemas.TrailSearchPayloadSchema = Body(...),
               context: schemas.CurrentContext = Depends(OR_context)):
    return {
        'data': traces.get_all(tenant_id=context.tenant_id, data=data)
    }


@app.post('/trails/actions', tags=["traces", "trails"], dependencies=[OR_role("owner", "admin")])
def get_available_trail_actions(context: schemas.CurrentContext = Depends(OR_context)):
    return {'data': traces.get_available_actions(tenant_id=context.tenant_id)}


@app.put('/{projectId}/assist/save', tags=["assist"])
def sign_record_for_upload(projectId: int, data: schemas.AssistRecordPayloadSchema = Body(...),
                           context: schemas.CurrentContext = Depends(OR_context)):
    if not sessions.session_exists(project_id=projectId, session_id=data.session_id):
        return {"errors": ["Session not found"]}
    return {"data": assist_records.presign_record(project_id=projectId, data=data, context=context)}


@app.put('/{projectId}/assist/save/done', tags=["assist"])
def save_record_after_upload(projectId: int, data: schemas.AssistRecordSavePayloadSchema = Body(...),
                             context: schemas.CurrentContext = Depends(OR_context)):
    if not sessions.session_exists(project_id=projectId, session_id=data.session_id):
        return {"errors": ["Session not found"]}
    return {"data": {"URL": assist_records.save_record(project_id=projectId, data=data, context=context)}}


@app.post('/{projectId}/assist/records', tags=["assist"])
def search_records(projectId: int, data: schemas.AssistRecordSearchPayloadSchema = Body(...),
                   context: schemas.CurrentContext = Depends(OR_context)):
    return {"data": assist_records.search_records(project_id=projectId, data=data, context=context)}


@app.get('/{projectId}/assist/records/{recordId}', tags=["assist"])
def get_record(projectId: int, recordId: int, context: schemas.CurrentContext = Depends(OR_context)):
    return {"data": assist_records.get_record(project_id=projectId, record_id=recordId, context=context)}


@app.post('/{projectId}/assist/records/{recordId}', tags=["assist"])
def update_record(projectId: int, recordId: int, data: schemas.AssistRecordUpdatePayloadSchema = Body(...),
                  context: schemas.CurrentContext = Depends(OR_context)):
    result = assist_records.update_record(project_id=projectId, record_id=recordId, data=data, context=context)
    if "errors" in result:
        return result
    return {"data": result}


@app.delete('/{projectId}/assist/records/{recordId}', tags=["assist"])
def delete_record(projectId: int, recordId: int, _=Body(None),
                  context: schemas.CurrentContext = Depends(OR_context)):
    result = assist_records.delete_record(project_id=projectId, record_id=recordId, context=context)
    if "errors" in result:
        return result
    return {"data": result}


@app.post('/{projectId}/signals', tags=['signals'])
def send_interactions(projectId: int, data: schemas.SignalsSchema = Body(...),
                      context: schemas.CurrentContext = Depends(OR_context)):
    data = signals.handle_frontend_signals_queued(project_id=projectId, user_id=context.user_id, data=data)

    if "errors" in data:
        return data
    return {'data': data}


@public_app.get('/{project_id}/assist-stats/avg', tags=["assist-stats"])
def get_assist_stats_avg(
        project_id: int,
        startTimestamp: int = None,
        endTimestamp: int = None,
        userId: str = None
):
    return assist_stats.get_averages(
        project_id=project_id,
        start_timestamp=startTimestamp,
        end_timestamp=endTimestamp,
        user_id=userId)


@public_app.get(
    '/{project_id}/assist-stats/top-members',
    tags=["assist-stats"],
    response_model=schemas.AssistStatsTopMembersResponse
)
def get_assist_stats_top_members(
        project_id: int,
        startTimestamp: int = None,
        endTimestamp: int = None,
        sort: Optional[str] = Query(default="sessionsAssisted",
                                    description="Sort options: " + ", ".join(assist_stats.event_type_mapping)),
        order: str = "desc",
        userId: int = None,
        page: int = 0,
        limit: int = 5
):
    return assist_stats.get_top_members(
        project_id=project_id,
        start_timestamp=startTimestamp,
        end_timestamp=endTimestamp,
        sort_by=sort,
        sort_order=order,
        user_id=userId,
        page=page,
        limit=limit
    )


@public_app.post(
    '/{project_id}/assist-stats/sessions',
    tags=["assist-stats"],
    response_model=schemas.AssistStatsSessionsResponse
)
def get_assist_stats_sessions(
        project_id: int,
        data: schemas.AssistStatsSessionsRequest = Body(...),
):
    return assist_stats.get_sessions(
        project_id=project_id,
        data=data
    )
