from datetime import UTC, datetime
from json import dumps
from logging import getLogger
from typing import Annotated

from fastapi import APIRouter, Body, Depends, UploadFile, status

from apps.tdn.auth import token
from apps.users.auth import login
from apps.users.models import User
from clients import clients as c
from clients.tmk import schema as ts
from clients.vitacore import schema as vs
from shared import exceptions as e
from shared.redis import client as cache

logger = getLogger(__name__)
router = APIRouter(
    prefix='/user',
    tags=[
        'User',
    ],
)


@router.get('/getProfile', response_model=vs.ProfileModel)
async def get_profile(user: Annotated[User, Depends(login)]):
    """
    Get profile of user.
    """
    return await c.vitacore_api.getProfile(user.vita_id)


@router.get(
    '/getDepartments',
    responses={
        status.HTTP_200_OK: {'model': vs.OrganizationsModel},
    },
)
async def get_departments():
    """
    Get list of departments.
    """
    return await c.vitacore_api.getDepartments()


@router.get('/getWorkers', response_model=vs.WorkersModel)
async def get_workers(
    user: Annotated[User, Depends(login)], departmentId: str
):
    """
    Get list of workers by department id.
    """
    return await c.vitacore_api.getWorkers(departmentId)


@router.get('/getSpecs', response_model=vs.SpecsV021Model)
async def get_specs(user: Annotated[User, Depends(login)]):
    """
    Get list of specialties.
    """
    return await c.vitacore_api.getSpecsV021()


@router.get('/getEntries', response_model=vs.EntriesModel)
async def get_entries(user: Annotated[User, Depends(login)]):
    """
    Get list of entries for user by id.
    """
    return await c.vitacore_api.getEntries(user.vita_id)


@router.get('/getVaccsReport')
async def get_vaccs_report(
    user: Annotated[User, Depends(login)], resultId: str | None = None
):
    """
    Get report of vaccinations for user by id.
    """
    if resultId is not None:
        return await c.vitacore_api.getDiagResultFile(resultId)

    return await c.vitacore_api.getVaccsReport(user.vita_id)


@router.get('/getMedExamDict')
async def get_med_exam_dict(user: Annotated[User, Depends(login)]):
    """
    Get medical examination dictionary.
    """
    return await c.vitacore_api.getMedExamDict()


@router.get('/getRoutesList')
async def get_routes_list(user: Annotated[User, Depends(login)]):
    """
    Get list of routes.
    """
    return await c.vitacore_api.getRoutesList(user.vita_id)


@router.get('/getHospExaminations')
async def get_hosp_examinations(
    user: Annotated[User, Depends(login)], examId: str | None = None
):
    """
    Get list of hospital examinations.
    """
    return await c.vitacore_api.getHospExaminations(
        user.vita_id,
        examId,
    )


@router.get('/getCurrHosp')
async def get_curr_hosp(user: Annotated[User, Depends(login)]):
    """
    Get current hospitalization.
    """
    return await c.vitacore_api.getCurrHosp(user.vita_id)


@router.get('/getHosps')
async def get_hosps(user: Annotated[User, Depends(login)]):
    """
    Get list of hospitals.
    """
    return await c.vitacore_api.getHosps(user.vita_id)


@router.get('/getHospRecommendations')
async def get_hosp_recommendations(user: Annotated[User, Depends(login)]):
    """
    Get list of recommended hospitals.
    """
    return await c.vitacore_api.getHospRecommendations(user.vita_id)


@router.get('/getHospRoutes')
async def get_hosp_routes(user: Annotated[User, Depends(login)]):
    """
    Get list of recommended hospitals.
    """
    return await c.vitacore_api.getHospRoutes(user.vita_id)


@router.get('/getDiagnosticResults')
async def get_diagnostic_results(user: Annotated[User, Depends(login)]):
    """
    Get list of diagnostic results.
    """
    return await c.vitacore_api.getDiagnosticResults(user.vita_id)


@router.get('/getELNs')
async def get_eln(user: Annotated[User, Depends(login)]):
    """
    Get list of ELNs.
    """
    return await c.vitacore_api.getELNs(user.vita_id)


@router.get('/getPatFLG')
async def get_pat_flg(user: Annotated[User, Depends(login)]):
    """
    Get list of ELNs.
    """
    return await c.vitacore_api.getPatFLG(user.vita_id)


@router.get('/queue', response_model=list[ts.QueueModel])
async def queue(_: Annotated[User, Depends(login)]):
    """
    Get list of VKS queues.
    """
    return await c.tmk_api.getQueue()


@router.get('/aemd')
async def aemd(user: Annotated[User, Depends(login)]):
    profile = await c.vitacore_api.getProfile(user.vita_id)
    snils = profile.SNILS.replace('-', '').replace(' ', '')
    docs = await c.aemd_api.searchRegistryItem(patient_snils=snils)
    doc = docs['items'][0]

    from datetime import datetime

    msg = f'AEMD Current datetime: {datetime.now(UTC).isoformat()}'
    logger.info(msg)

    return await c.aemd_api.demandContent(
        messageId='test123', emdrId=doc['emdrId']
    )


@router.post('/measurement', status_code=status.HTTP_202_ACCEPTED)
async def measurement(
    tdn_access_token: Annotated[str, Depends(token)],
    user: Annotated[User, Depends(login)],
    ad: Annotated[int, Body()],
    sd: Annotated[int, Body()],
    pulse: Annotated[int, Body()],
    comment: Annotated[str, Body()],
    status: Annotated[int, Body(ge=1, le=3)],
    serial_number: Annotated[str, Body()],
    ekg: UploadFile,
):
    # patient = await c.tdn_api.patient_search(tdn_access_token, user.vita_id)
    patientUid = 'e5708e5a-62e0-4318-a510-7860a31d92d9'
    observations = await c.tdn_api.observations_search(
        tdn_access_token, patientUid
    )

    if observations.total == 0:
        raise e.NotFoundException(detail='No observations found')

    ad_obsrvMeasurementUid = None
    ad_observationUid = None
    health_obsrvMeasurementUid = None
    health_observationUid = None

    sad_measurement = None
    dad_measurement = None
    pulse_measurement = None
    health_measurement = None
    health_measurement_created_at = None

    observations = observations.items[::-1]
    for observation in observations:
        observation_measurements = (
            await c.tdn_api.observations_measurement_search(
                tdn_access_token, observation.uid
            )
        )

        for measurement in observation_measurements.items:
            if measurement.measurement.code == 'ADPULSE':
                ad_obsrvMeasurementUid = measurement.uid
                ad_observationUid = measurement.observationUid

                for metric in measurement.obsrvMtMetrics:
                    if metric.metric.code == 'SAD':
                        sad_measurement = metric.uid

                    if metric.metric.code == 'DAD':
                        dad_measurement = metric.uid

                    if metric.metric.code == 'PULSE':
                        pulse_measurement = metric.uid

            if measurement.measurement.code == 'HEALTH':
                health_obsrvMeasurementUid = measurement.uid
                health_observationUid = measurement.observationUid

                for metric in measurement.obsrvMtMetrics:
                    if metric.metric.code == 'HEALTH' and (
                        health_measurement_created_at is None
                        or metric.createdAt > health_measurement_created_at
                    ):
                        health_measurement = metric.uid
                        health_measurement_created_at = metric.createdAt

        if (
            not ad_obsrvMeasurementUid
            or not sad_measurement
            or not dad_measurement
            or not pulse_measurement
            or not ad_observationUid
            or not health_obsrvMeasurementUid
            or not health_observationUid
            or not health_measurement
            or not health_measurement_created_at
        ):
            ad_obsrvMeasurementUid = None
            sad_measurement = None
            dad_measurement = None
            pulse_measurement = None
            ad_observationUid = None
            health_obsrvMeasurementUid = None
            health_observationUid = None
            health_measurement = None
            health_measurement_created_at = None

        else:
            break

    if not ad_obsrvMeasurementUid or not ad_observationUid:
        raise e.NotFoundException(detail='No ADPULSE measurement found')

    if not sad_measurement:
        raise e.NotFoundException(detail='No SAD measurement found')

    if not dad_measurement:
        raise e.NotFoundException(detail='No DAD measurement found')

    if not pulse_measurement:
        raise e.NotFoundException(detail='No PULSE measurement found')

    if not health_obsrvMeasurementUid or not health_observationUid:
        raise e.NotFoundException(detail='No HEALTH measurement found')

    if not health_measurement:
        raise e.NotFoundException(detail='No HEALTH measurement found')

    if not health_obsrvMeasurementUid or not health_observationUid:
        raise e.NotFoundException(detail='No HEALTH measurement found')

    ad_series = await c.tdn_api.create_series(
        tdn_access_token,
        ad_observationUid,
        ad_obsrvMeasurementUid,
    )

    ad_series_uid = ad_series.uid

    # SAD
    await c.tdn_api.create_series_values(
        tdn_access_token, ad_series_uid, sad_measurement, nvalue=sd
    )

    # DAD
    await c.tdn_api.create_series_values(
        tdn_access_token, ad_series_uid, dad_measurement, nvalue=ad
    )

    # PULSE
    await c.tdn_api.create_series_values(
        tdn_access_token, ad_series_uid, pulse_measurement, nvalue=pulse
    )

    health_series = await c.tdn_api.create_series(
        tdn_access_token,
        health_observationUid,
        health_obsrvMeasurementUid,
    )

    health_series_uid = health_series.uid

    # HEALTH
    await c.tdn_api.create_series_values(
        tdn_access_token,
        health_series_uid,
        health_measurement,
        nvalue=status,
        svalue=comment,
    )

    # EKG
    await c.tdn_api.ekg(
        tdn_access_token,
        patientUid,
        serial_number,
        ekg,
    )

    created = datetime.now(UTC).strftime('%Y-%m-%d %H:%M:%S')
    data = {
        'ad': ad,
        'sd': sd,
        'pulse': pulse,
        'created_at': created,
        'comment': comment,
        'status': status,
    }
    cache_key = f'tdn:measurement:{user.id}:{created}'
    await cache.set(cache_key, dumps(data))


@router.get('/measurements')
async def measurements(
    user: Annotated[User, Depends(login)],
):
    data = [
        cache.get(key)
        for key in await cache.keys(f'tdn:measurement:{user.id}:*')
    ]
    return data
