from pathlib import Path
from fastapi import APIRouter, Depends, HTTPException
from api.n3health import resend, revoke, sendForSigning
from db.schemas.documents import Document
from db.schemas.patients import Patient
from db.schemas.practitioners import Practitioner
from db.schemas.settings import Settings
from db.schemas.signings import Signing
from db.schemas.statuses import Statuses
from utils import requestDict, logger, convert_docs_to_pdfs
from utils.attachment import pdfGet

router = APIRouter()


@router.get("/health", summary="Health")
async def health():
    return {"status": "healthy"}


@router.post("/pre_singing", summary="pre_singing")
async def pre_singing(
    reqData: dict = Depends(requestDict),
):
    # signature - type: eSignature / eAttorney

    logger.info(f"📥 Получен запрос на /pre_singing")

    practitioner = await Practitioner.getPractitionerByIdLpu(
        reqData.get("body", {}).get("userId", 0)
    )
    signature = {}
    if practitioner.success:
        signature["type"] = (
            "eSignature" if practitioner.data.get("esiaAuth", False) else "eAttorney"
        )
        signature["expiration"] = practitioner.data.get("expired_at")[:10]

    daysRemainingControl = 0
    settings = await Settings.getSettings()
    if settings.success:
        daysRemainingControl = settings.data.get("expirationAlert", 0)

    inProgress = []
    complete = []

    idPatientMis = reqData.get("body", {}).get("patientId", 0)
    if type(idPatientMis) != str:
        idPatientMis = str(idPatientMis)
    patient = await Patient.getPatientByIdPatientMis(idPatientMis, False, True)

    if patient.success:
        docNumbers = reqData.get("body", {}).get("docNumbers", [])
        for docNumber in docNumbers:
            if type(docNumber) != int:
                docNumber = int(docNumber)
            docs = await Document.getDocumentsByIdPatientMisAndNumber(
                idPatientMis, docNumber, True
            )
            if docs.success:
                for doc in docs.data:
                    docSingingId = doc.singingId
                    docSinging = await Signing.getSigningById(docSingingId)
                    if docSinging.success:
                        if docSinging.data.get("storagePath"):
                            complete.append(docNumber)
                        else:
                            if docSinging.data.get("trackingId"):
                                inProgress.append(docNumber)
            else:
                logger.info(f"✅ {docNumber} - {docs.message}")

    exitData = {
        "signature": signature,
        "inProgress": inProgress,
        "complete": complete,
        "daysRemainingControl": daysRemainingControl,
    }
    return exitData


@router.post("/singing", summary="singing")
async def singing(
    reqData: dict = Depends(requestDict),
):
    def correctData(data):
        data["practitioner"]["userIdLpu"] = str(data["practitioner"]["userIdLpu"])
        for patient in data["patients"]:
            patient["idPatientMis"] = str(patient["idPatientMis"])
        return data

    logger.info(f"📥 Получен запрос на /singing")

    # Получаем данные из запроса
    body = reqData.get("body", {})
    docs = body.pop("docs", [])

    # Проверяем наличие документов
    if not docs:
        logger.warning("Нет документов для обработки")
        return {"status": "ERROR", "message": "Нет документов для обработки"}

    practitioner = await Practitioner.getPractitionerByIdLpu(
        body.get("practitioner", {}).get("userIdLpu", 0)
    )
    if not practitioner.success:
        logger.error(
            f"Сотрудник не найден, idLpu: {body.get('practitioner', {}).get('userIdLpu', 0)}"
        )
        return {"status": "ERROR", "message": "Сотрудник не найден"}
    esiaAuth = practitioner.data.get("esiaAuth", False)
    userIdLpu = practitioner.data.get("userIdLpu", 0)

    patients = body.get("patients", [])
    if len(patients) == 0:
        logger.error("Данные пациента не получены, пациент не найден")
        return {
            "status": "ERROR",
            "message": "Данные пациента не получены, пациент не найден",
        }

    patientsData = []

    for patient in patients:
        idPatientMis = patient.get("idPatientMis", None)
        if not idPatientMis:
            logger.error("Не указан идентификатор пациента")
            return {
                "status": "ERROR",
                "message": "Не указан идентификатор пациента",
            }
        patientDB = await Patient.getPatientByIdPatientMis(idPatientMis, isCheck=True)
        if not patientDB.success:
            patientData = {
                "idPatientMis": idPatientMis,
                "familyName": patient.get("familyName", "N/A"),
                "givenName": patient.get("givenName", "N/A"),
                "middleName": patient.get("middleName", "N/A"),
                "birthDate": patient.get("birthDate", "N/A"),
                "sex": patient.get("sex", "N/A"),
            }
            newPatient = await Patient.addPatient(**patientData)
            if not newPatient.success:
                return {
                    "status": "ERROR",
                    "message": newPatient.message,
                }
            patientsData.append(newPatient.data.toDict())
        else:
            patientsData.append(patientDB.data)

    # Логируем информацию о документах
    logger.info(f"👨‍⚕️ Медработник: {practitioner.data.get("name")}")
    logger.info(
        f"👥 Пациенты ({len(patientsData)}): {', '.join([f'{p.get('name')}' for p in patientsData])}"
    )
    logger.info(f"📄 Документов для обработки: {len(docs)}")
    logger.info(f"🔐 ЕСИА: {esiaAuth}")

    try:
        # Конвертируем документы в PDF
        conversion_result = convert_docs_to_pdfs(docs, patientsData)
        # logger.info(conversion_result)

        if conversion_result.get("status", "") != "SUCCESS":
            return {
                "status": "ERROR",
                "message": "Не удалось сохранить документы",
            }

        newSinging = await Signing.addSigning(userIdLpu, idPatientMis)
        if not newSinging:
            return {
                "status": "ERROR",
                "message": "Не удалось добавить подписание",
            }
        logger.info(f"🔐 Подписание добавлено: {newSinging.id}")

        pdfFiles = conversion_result.get("files", {})
        body["medDocument"] = {
            "esiaAuth": esiaAuth,
            "attachments": [],
        }
        body["files"] = []
        for key in pdfFiles:
            pdfFile = pdfFiles[key]
            for doc in pdfFile:
                newDocument = await Document.addDocument(
                    singingId=newSinging.id, idPatientMis=key, **doc
                )
                if not newDocument:
                    return {
                        "status": "ERROR",
                        "message": "Не удалось добавить документ",
                    }
                logger.info(f"📄 Документ добавлен: {newDocument.id}")
                partName = f'file{len(body["medDocument"]["attachments"])}'
                body["medDocument"]["attachments"].append(
                    {
                        "partName": partName,
                    }
                )
                body["files"].append(
                    {
                        "field": partName,
                        "path": Path(doc["storagePath"]),
                        "content_type": "application/pdf",
                    }
                )

        if esiaAuth:
            partName = f'file{len(body["medDocument"]["attachments"])}'
            body["medDocument"]["attachments"].append(
                {
                    "partName": partName,
                }
            )
            body["files"].append(
                {
                    "field": partName,
                    "path": Path(
                        f"src/attachments/secure/{userIdLpu}/signature.p7s"
                    ).resolve(),
                    "content_type": "application/pkcs7-signature",
                }
            )

        signingResult = await sendForSigning(correctData(body))
        if not signingResult or signingResult.get("status", "") != "created":
            return {
                "status": "ERROR",
                "message": "Не удалось отправить документы на подписание",
            }

        newSinging.trackingId = signingResult.get("trackingId", "")
        await newSinging.save()
        logger.info(
            f"🔐 Подписание обновлено: {newSinging.id}. Добавлен Трек-номер подписания"
        )

        await Statuses.updateStatus(newSinging.id, True)

        logger.info(f"✅ Обработка завершена!")

        # Возвращаем ответ
        response = {
            "status": "SUCCESS",
            "message": f"Документы успешно обработаны. Трек-номер подписания: {newSinging.trackingId}",
        }

        return response

    except Exception as e:
        error_msg = f"Ошибка при обработке документов: {str(e)}"
        logger.error(error_msg)
        raise HTTPException(status_code=500, detail=error_msg)


@router.post("/statuses", summary="statuses")
async def statuses(
    reqData: dict = Depends(requestDict),
):
    logger.info(f"📥 Получен запрос на /statuses")

    # Получаем данные из запроса
    body = reqData.get("body", {})

    userIdLpu = str(body.get("userIdLpu"))
    filters = body.get("filters", {})
    if not userIdLpu or not filters:
        logger.error("Не отправлены userIdLpu или filters")
        return {"status": "ERROR", "message": "Не отправлены необходимые данные"}

    result = await Signing.getFilteredSingings(userIdLpu, filters)
    singingsData = result.data

    return singingsData


@router.post("/documents", summary="documents")
async def documents(
    reqData: dict = Depends(requestDict),
):
    logger.info(f"📥 Получен запрос на /documents")

    # Получаем данные из запроса
    body = reqData.get("body", {})

    if "idPatientMis" not in body:
        logger.error("Не отправлен idPatientMis")
        return {"status": "ERROR", "message": "Не отправлен idPatientMis"}

    idPatientMis = body.get("idPatientMis")

    singingData = await Signing.getSigningsByIdPatientMis(idPatientMis)

    if not singingData.success:
        logger.error("Подписания не найдены")
        return {"status": "SUCCESS", "data": [], "message": "Подписания не найдены"}

    userIdLpus = set([s.get("userIdLpu") for s in singingData.data])

    practitioners = {}
    for userIdLpu in userIdLpus:
        practitioner = await Practitioner.getPractitionerByIdLpu(userIdLpu, False)
        practitioners[userIdLpu] = practitioner.data.name

    for s in singingData.data:
        s["practitioner"] = practitioners[s.get("userIdLpu")]

    responseData = {"status": "SUCCESS", "data": singingData.data}

    return responseData


@router.post("/document", summary="document")
async def document(
    reqData: dict = Depends(requestDict),
):
    logger.info(f"📥 Получен запрос на /document")

    documentPath = reqData.get("body", {}).get("documentPath", None)
    if not documentPath:
        return {"status": "ERROR", "message": "Документ не найден"}

    docBytes = pdfGet(documentPath)
    if not docBytes.success:
        return {"status": "ERROR", "message": docBytes.message}

    return {"status": "SUCCESS", "data": docBytes.data}


@router.post("/revoke", summary="revoke")
async def revoke_post(
    reqData: dict = Depends(requestDict),
):
    logger.info(f"📥 Получен запрос на /revoke")
    trackingId = reqData.get("body", {}).get("trackingId", None)
    if not trackingId:
        return {"status": "ERROR", "message": "Документ не найден"}

    revokeResult = await revoke(trackingId)
    if revokeResult.get("status", "") != "success":
        return {
            "status": "ERROR",
            "message": revokeResult.get("errorMessage", "Отозвать не удалось"),
        }

    import asyncio

    await asyncio.sleep(2)
    await Signing.updateStatuses()

    return {"status": "SUCCESS", "message": "Документ отозван"}


@router.post("/resend", summary="resend")
async def resend_post(
    reqData: dict = Depends(requestDict),
):
    logger.info(f"📥 Получен запрос на /resend")
    trackingId = reqData.get("body", {}).get("trackingId", None)
    idPatientMis = reqData.get("body", {}).get("idPatientMis", None)

    errorResponse = {"status": "ERROR", "message": "Повторная отправка не удалось"}
    if not trackingId or not idPatientMis:
        logger.error("Не отправлен trackingId или idPatientMis")
        logger.error(f"trackingId: {trackingId}, idPatientMis: {idPatientMis}")
        return errorResponse

    resendResult = await resend(trackingId, idPatientMis)

    if not resendResult or not resendResult.get("status", ""):
        logger.error(resendResult)
        return errorResponse

    newTrackingId = resendResult.get("tracking_id", "")
    singingId = reqData.get("body", {}).get("id", "")

    if not newTrackingId or not singingId:
        logger.error("Не отправлен trackingId или id")
        logger.error(f"trackingId: {newTrackingId}, id: {singingId}")
        return errorResponse

    singing = await Signing.getSigningById(singingId)
    if not singing.success:
        logger.error(singing.message)
        return errorResponse

    await singing.data.edit(trackingId=newTrackingId)
    logger.info("✅ Повторная отправка успешна")

    return {"status": "SUCCESS", "message": resendResult.get("message", "")}


@router.post("/advanced-search", summary="advanced-search")
async def advanced_search_post(
    reqData: dict = Depends(requestDict),
):
    logger.info(f"📥 Получен запрос на /advanced-search")

    result = await Signing.getFilteredSingings(
        "", reqData.get("body", {}).get("filters", {})
    )
    return {"status": "SUCCESS", "data": result.data}
