from pathlib import Path
from fastapi import APIRouter, Depends, HTTPException
from api.medods import findPatientByPhone
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
    deliveryType = None
    settings = await Settings.getSettings()
    if settings.success:
        daysRemainingControl = settings.data.get("expirationAlert", 0)
        deliveryData = settings.data.get("deliveryType", {})
        deliveryType = [k for k, v in deliveryData.items() if v]
        multipleSending = settings.data.get("multipleSending", False)

    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,
        "deliveryType": deliveryType,
        "multipleSending": multipleSending,
    }
    return exitData


@router.post("/singing", summary="singing")
async def singing(
    reqData: dict = Depends(requestDict),
):
    def correctData(data):
        data["practitioner"]["userIdLpu"] = str(data["practitioner"]["userIdLpu"])
        data["patient"]["idPatientMis"] = str(data["patient"]["idPatientMis"])
        for recipient in data.get("recipients", []):
            recipient["idPatientMis"] = str(recipient["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)
    body["practitioner"]["snils"] = practitioner.data.get("snils")
    if not esiaAuth:
        body["practitioner"]["mrProxyNumber"] = practitioner.data.get("attorney")

    patient = body.get("patient", None)
    if not patient:
        logger.error("Данные пациента не получены, пациент не найден")
        return {
            "status": "ERROR",
            "message": "Данные пациента не получены, пациент не найден",
        }
    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": "Не удалось создать пациента",
            }
        patientData = newPatient.data.toDict()
    else:
        patientData = patientDB.data

    recipients = body.pop("recipients", [])

    recipientsData = []
    recipientsIds = []

    for recipient in recipients:
        idRecipientMis = recipient.get("idPatientMis", None)
        if not idRecipientMis:
            logger.error("Не указан идентификатор пациента")
            return {
                "status": "ERROR",
                "message": "Не указан идентификатор пациента",
            }
        recipientDB = await Patient.getPatientByIdPatientMis(
            idRecipientMis, isCheck=True
        )
        if not recipientDB.success:
            recipientData = {
                "idPatientMis": idRecipientMis,
                "familyName": recipient.get("surname", "N/A"),
                "givenName": recipient.get("name", "N/A"),
                "middleName": recipient.get("secondName", "N/A"),
                "birthDate": recipient.get("birthDate", "N/A"),
                "sex": recipient.get("sex", "N/A"),
            }
            newRecipient = await Patient.addPatient(**recipientData)
            if not newRecipient.success:
                return {
                    "status": "ERROR",
                    "message": newRecipient.message,
                }
            recipientsData.append(newRecipient.data.toDict())
            recipientsIds.append(newRecipient.data.idPatientMis)
        else:
            logger.info(recipientDB.data)
            recipientsData.append(recipientDB.data)
            recipientsIds.append(recipientDB.data.get("idPatientMis"))

        recipient["documentDto"] = [
            {
                "docN": recipient.pop("snils"),
                "docS": "",
                "documentName": "СНИЛС",
                "idDocumentType": 223,
                "providerName": "ПФР",
            }
        ]
        recipient["telecom"] = [
            {
                "system": "Telephone",
                "value": f'+{recipient.pop("phone")}',
            }
        ]
    body["recipients"] = recipients

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

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

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

        newSinging = await Signing.addSigning(
            userIdLpu, idPatientMis, body["deliveryType"], recipientsIds
        )
        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 doc in pdfFiles:
            for idPatient in [idPatientMis, *recipientsIds]:
                newDocument = await Document.addDocument(
                    singingId=newSinging.id, idPatientMis=str(idPatient), **doc
                )
                if not newDocument:
                    logger.error(
                        f"Не удалось добавить документ для получателя {idPatient}"
                    )
                    return {
                        "status": "ERROR",
                        "message": "Не удалось добавить документ",
                    }
                logger.debug(
                    f"📄 Документ добавлен: {newDocument.id} для получателя {idPatient}"
                )
            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.debug(
            f"🔐 Подписание обновлено: {newSinging.id}. Добавлен Трек-номер подписания"
        )

        await Statuses.updateStatus(newSinging.id, True)

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

        response = {
            "status": "SUCCESS",
            "message": "Документы успешно обработаны.",
        }

        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

    for singingData in singingsData:
        documents = singingData.pop("documents", [])
        uniqueDocs = []
        uniquePaths = []
        for doc in documents:
            if doc.get("storagePath") not in uniquePaths:
                uniquePaths.append(doc.get("storagePath"))
                uniqueDocs.append(doc)
        singingData["documents"] = uniqueDocs

    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 = str(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")]

    for singing in singingData.data:
        statusesData = [
            {d.get("idPatientMis"): d.get("patient", {}).get("name")}
            for d in singing.get("statuses", [])
            if d.get("idPatientMis")
        ]
        idMatchName = {}
        for statusData in statusesData:
            for idPatientMisStatus, name in statusData.items():
                if idPatientMisStatus in idMatchName:
                    continue
                idMatchName[idPatientMisStatus] = name

        documents = singing.pop("documents")
        uniqueDocs = []
        for doc in documents:
            docOwner = doc.get("storagePath").split("/")[-2:-1][0]
            isOwn = docOwner == idPatientMis
            if str(doc.get("idPatientMis")) == idPatientMis:
                if not isOwn:
                    ownerName = idMatchName[docOwner]
                    doc["title"] = (
                        f"{doc.get('title')} (Пациент: {idMatchName[docOwner]})"
                    )
                uniqueDocs.append(doc)
        singing["documents"] = uniqueDocs

    settings = await Settings.getSettings(False)

    data = {"deliveryType": settings.data.deliveryType, "singings": singingData.data}

    responseData = {"status": "SUCCESS", "data": 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)
    deliveryType = reqData.get("body", {}).get("deliveryType", None)

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

    resendResult = await resend(trackingId, idPatientMis, deliveryType)

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

    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")

    filters = reqData.get("body", {}).get("filters", {})
    result = await Signing.getFilteredSingings("", filters)

    for singingData in result.data:
        documents = singingData.pop("documents", [])
        uniqueDocs = []
        uniquePaths = []
        for doc in documents:
            if doc.get("storagePath") not in uniquePaths:
                uniquePaths.append(doc.get("storagePath"))
                uniqueDocs.append(doc)
        singingData["documents"] = uniqueDocs

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


@router.post("/search-recipients", summary="search-recipients")
async def search_recipients_post(
    reqData: dict = Depends(requestDict),
):
    logger.info(f"📥 Получен запрос на /search-recipients")
    phoneNumber = "".join(
        filter(str.isdigit, reqData.get("body", {}).get("phone", ""))
    )[-10:]
    idPatientMis = str(reqData.get("body", {}).get("idPatientMis", ""))

    settings = await Settings.getSettings(False)
    if not settings.success:
        logger.error(settings.error)
        return {"status": "error", "message": settings.error}
    settings = settings.data
    try:
        patientsDB = await findPatientByPhone(
            settings.medodsApiHost,
            settings.medodsApiPort,
            settings.medodsApiIdentity,
            settings.medodsApiSecretKey,
            f"7{phoneNumber}",
        )
        if not patientsDB.success or patientsDB.data.get("totalItems") == 0:
            logger.error("Пациент не найден")
            return {"status": "error", "data": []}
        patients = patientsDB.data.get("data", [])
        result = [
            {
                "idPatientMis": str(patient.get("id")),
                "name": patient.get("name"),
                "surname": patient.get("surname"),
                "secondName": patient.get("secondName"),
                "birthDate": patient.get("birthdate"),
                "sex": patient.get("sex"),
                "snils": patient.get("snils"),
                "phone": patient.get("phone"),
            }
            for patient in patients
            if str(patient.get("id")) != idPatientMis
        ]
        return {
            "status": "ok",
            "data": result,
        }
    except Exception as e:
        logger.error(e)
        return {
            "status": "error",
            "data": [],
        }
