"""
Integrations views and viewsets
"""

import logging
from datetime import datetime

from rest_framework import status, views, viewsets
from rest_framework.decorators import action
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response

from apps.accounts.permissions import IsPXAdmin
from apps.core.services import AuditService

from .models import EventMapping, HISTestPatient, HISTestVisit, InboundEvent, IntegrationConfig
from .serializers import (
    EventMappingSerializer,
    HISPatientDataSerializer,
    IntegrationConfigSerializer,
)
from .services.his_adapter import HISAdapter

logger = logging.getLogger("apps.integrations")


class HISPatientDataView(views.APIView):
    """
    API View for receiving complete HIS patient data.

    This replaces the old event-based approach. HIS systems send
    complete patient data including demographics and visit timeline.
    The system determines survey type from PatientType and sends
    appropriate survey via SMS.

    POST /api/integrations/events/ - Send complete HIS patient data

    Request Format:
    {
        "FetchPatientDataTimeStampList": [{...patient demographics...}],
        "FetchPatientDataTimeStampVisitDataList": [
            {"Type": "Consultation", "BillDate": "05-Jun-2025 11:06"},
            ...
        ],
        "Code": 200,
        "Status": "Success"
    }

    PatientType Codes:
    - "1" → Inpatient Survey
    - "2" or "O" → OPD Survey
    - "3" or "E" → EMS Survey
    - "4" or "D" → Day Case Survey

    Response Format:
    {
        "success": true,
        "message": "Patient data processed successfully",
        "patient": {
            "id": 123,
            "mrn": "878943",
            "name": "AFAF NASSER ALRAZoooOOQ"
        },
        "patient_type": "1",
        "survey": {
            "id": 456,
            "status": "SENT",
            "survey_url": "https://..."
        },
        "survey_sent": true
    }
    """

    permission_classes = []  # Allow public access for HIS integration

    def post(self, request):
        """Process HIS patient data and create/send survey"""
        # Validate HIS data format
        serializer = HISPatientDataSerializer(data=request.data)

        if not serializer.is_valid():
            return Response(
                {"success": False, "error": "Invalid HIS data format", "details": serializer.errors},
                status=status.HTTP_400_BAD_REQUEST,
            )

        his_data = serializer.validated_data

        # Log the incoming data
        patient_list = his_data.get("FetchPatientDataTimeStampList", [])
        patient_data = patient_list[0] if patient_list else {}
        patient_id = patient_data.get("PatientID", "Unknown")
        patient_type = patient_data.get("PatientType", "Unknown")

        logger.info(f"HIS patient data received: PatientID={patient_id}, PatientType={patient_type}")

        # Process HIS data using HISAdapter
        result = HISAdapter.process_his_data(his_data)

        # Create audit log
        if result["success"]:
            AuditService.log_from_request(
                event_type="his_integration",
                description=(
                    f"HIS patient data processed: PatientID={patient_id}, "
                    f"PatientType={patient_type}, "
                    f"Survey Sent={result.get('survey_sent', False)}"
                ),
                request=request,
                metadata={
                    "patient_id": patient_id,
                    "patient_type": patient_type,
                    "survey_sent": result.get("survey_sent", False),
                    "survey_id": result.get("survey").id if result.get("survey") else None,
                },
            )

        # Prepare response
        response_data = {"success": result["success"], "message": result["message"]}

        # Add patient info if available
        if result.get("patient"):
            patient = result["patient"]
            response_data["patient"] = {
                "id": patient.id,
                "mrn": patient.mrn,
                "name": f"{patient.first_name} {patient.last_name}".strip(),
            }
            response_data["patient_type"] = result.get("patient_type")

        # Add survey info if available
        if result.get("survey"):
            survey = result["survey"]
            response_data["survey"] = {"id": survey.id, "status": survey.status, "survey_url": survey.get_survey_url()}
            response_data["survey_sent"] = result.get("survey_sent", False)

        # Return appropriate status code
        if result["success"]:
            status_code = status.HTTP_200_OK
        else:
            status_code = status.HTTP_400_BAD_REQUEST

        return Response(response_data, status=status_code)


class InboundEventViewSet(viewsets.ModelViewSet):
    """
    Legacy ViewSet for Inbound Events (DEPRECATED).

    This viewset is kept for backward compatibility but is no longer
    the primary integration method. Use HISPatientDataView instead.
    """

    queryset = InboundEvent.objects.all()
    permission_classes = [IsAuthenticated, IsPXAdmin]
    filterset_fields = ["status", "source_system", "event_code", "encounter_id"]
    search_fields = ["encounter_id", "patient_identifier", "event_code"]
    ordering_fields = ["received_at", "processed_at"]
    ordering = ["-received_at"]

    def get_serializer_class(self):
        """Return appropriate serializer based on action"""
        from .serializers import (
            InboundEventSerializer,
            InboundEventListSerializer,
        )

        if self.action == "list":
            return InboundEventListSerializer
        return InboundEventSerializer

    @action(detail=False, methods=["post"], permission_classes=[IsPXAdmin])
    def bulk_create(self, request):
        """
        Bulk create events.

        DEPRECATED: This endpoint is kept for backward compatibility.
        Use HISPatientDataView for new integrations.
        """
        from .serializers import InboundEventCreateSerializer

        events_data = request.data.get("events", [])

        if not events_data:
            return Response({"error": "No events provided"}, status=status.HTTP_400_BAD_REQUEST)

        created_events = []
        errors = []

        for event_data in events_data:
            serializer = InboundEventCreateSerializer(data=event_data)
            if serializer.is_valid():
                event = serializer.save()
                created_events.append(event)
            else:
                errors.append({"data": event_data, "errors": serializer.errors})

        return Response(
            {
                "created": len(created_events),
                "failed": len(errors),
                "errors": errors,
                "message": "This endpoint is deprecated. Use HISPatientDataView for new integrations.",
            },
            status=status.HTTP_201_CREATED if created_events else status.HTTP_400_BAD_REQUEST,
        )


class IntegrationConfigViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Integration Configurations.

    Permissions:
    - Only PX Admins can manage integration configurations
    """

    queryset = IntegrationConfig.objects.all()
    serializer_class = IntegrationConfigSerializer
    permission_classes = [IsPXAdmin]
    filterset_fields = ["source_system", "is_active"]
    search_fields = ["name", "description"]
    ordering_fields = ["name", "created_at"]
    ordering = ["name"]

    def get_queryset(self):
        return super().get_queryset().prefetch_related("event_mappings")


class EventMappingViewSet(viewsets.ModelViewSet):
    """
    ViewSet for Event Mappings.

    Permissions:
    - Only PX Admins can manage event mappings
    """

    queryset = EventMapping.objects.all()
    serializer_class = EventMappingSerializer
    permission_classes = [IsPXAdmin]
    filterset_fields = ["integration_config", "is_active"]
    search_fields = ["external_event_code", "internal_event_code"]
    ordering_fields = ["external_event_code"]
    ordering = ["integration_config", "external_event_code"]

    def get_queryset(self):
        return super().get_queryset().select_related("integration_config")


class TestHISDataView(views.APIView):
    """
    Test endpoint that mimics the real HIS API.

    GET /api/integrations/test-his-data/?FromDate=...&ToDate=...&SSN=...&MobileNo=...

    Reads from HISTestPatient/HISTestVisit tables (loaded via load_his_test_data command).
    Supports the same query parameters as the real HIS API:
    - FromDate / ToDate: Filter by AdmitDate range (format: DD-Mon-YYYY HH:MM:SS)
    - SSN: Filter by SSN ("0" = all)
    - MobileNo: Filter by MobileNo ("0" = all)
    """

    permission_classes = []

    def _parse_his_date(self, date_str):
        if not date_str:
            return None
        try:
            from django.utils import timezone

            naive = datetime.strptime(date_str, "%d-%b-%Y %H:%M:%S")
            return timezone.make_aware(naive)
        except ValueError:
            pass
        try:
            from django.utils import timezone

            naive = datetime.strptime(date_str, "%d-%b-%Y %H:%M")
            return timezone.make_aware(naive)
        except ValueError:
            return None

    def get(self, request):
        from_date_str = request.GET.get("FromDate")
        to_date_str = request.GET.get("ToDate")
        ssn = request.GET.get("SSN", "0")
        mobile_no = request.GET.get("MobileNo", "0")

        from_date = self._parse_his_date(from_date_str)
        to_date = self._parse_his_date(to_date_str)

        if from_date and to_date and to_date < from_date:
            return Response(
                {"Code": 400, "Status": "Error", "Message": "ToDate must be after FromDate"},
                status=status.HTTP_400_BAD_REQUEST,
            )

        qs = HISTestPatient.objects.all()

        if from_date:
            qs = qs.filter(admit_date__gte=from_date)

        if to_date:
            qs = qs.filter(admit_date__lte=to_date)

        if ssn and ssn != "0":
            qs = qs.filter(ssn=ssn)

        if mobile_no and mobile_no != "0":
            qs = qs.filter(mobile_no=mobile_no)

        patients = list(qs[:1000])
        admission_ids = [p.admission_id for p in patients]

        patient_list = [p.patient_data for p in patients]

        visits = HISTestVisit.objects.filter(admission_id__in=admission_ids)
        ed_visits = []
        ip_visits = []
        op_visits = []
        for v in visits:
            if v.visit_category == "ED":
                ed_visits.append(v.visit_data)
            elif v.visit_category == "IP":
                ip_visits.append(v.visit_data)
            elif v.visit_category == "OP":
                op_visits.append(v.visit_data)

        return Response(
            {
                "FetchPatientDataTimeStampList": patient_list,
                "FetchPatientDataTimeStampVisitEDDataList": ed_visits,
                "FetchPatientDataTimeStampVisitIPDataList": ip_visits,
                "FetchPatientDataTimeStampVisitOPDataList": op_visits,
                "Code": 200,
                "Status": "Success",
                "MobileNo": "",
                "Message": "",
                "Message2L": "",
            }
        )


class SimulateHISPayloadView(views.APIView):
    """
    POST endpoint to simulate receiving HIS data for testing.

    Accepts the same JSON format as the real HIS API response and:
    1. Stores patients/visits into HISTestPatient/HISTestVisit (persistent)
    2. Calls HISAdapter.process_his_response() to process everything
    3. Returns full processing results (surveys created, errors, etc.)

    POST /api/integrations/simulate-his-payload/
    Body: same as HIS response (visit_data.json format)

    After posting, the data will also be picked up by the regular
    fetch-his-surveys cron if the "HIS Test" IntegrationConfig is active.
    """

    permission_classes = [IsAuthenticated, IsPXAdmin]

    def _parse_date(self, date_str):
        if not date_str:
            return None
        try:
            naive = datetime.strptime(date_str, "%d-%b-%Y %H:%M")
            return timezone.make_aware(naive)
        except ValueError:
            pass
        try:
            naive = datetime.strptime(date_str, "%d-%b-%Y %H:%M:%S")
            return timezone.make_aware(naive)
        except ValueError:
            return None

    def post(self, request):
        payload = request.data
        if not isinstance(payload, dict):
            return Response({"detail": "Request body must be a JSON object"}, status=status.HTTP_400_BAD_REQUEST)

        patient_list = payload.get("FetchPatientDataTimeStampList", [])
        if not patient_list:
            return Response({"detail": "FetchPatientDataTimeStampList is empty"}, status=status.HTTP_400_BAD_REQUEST)

        ed_visits = payload.get("FetchPatientDataTimeStampVisitEDDataList", [])
        ip_visits = payload.get("FetchPatientDataTimeStampVisitIPDataList", [])
        op_visits = payload.get("FetchPatientDataTimeStampVisitOPDataList", [])

        admission_ids = [p.get("AdmissionID") for p in patient_list]
        admission_id_set = {aid for aid in admission_ids if aid}

        patients_stored = 0
        visits_stored = 0
        skipped_patients = 0

        existing_patients = set(
            HISTestPatient.objects.filter(admission_id__in=admission_id_set).values_list("admission_id", flat=True)
        )
        existing_visits = set(
            HISTestVisit.objects.filter(admission_id__in=admission_id_set).values_list(
                "admission_id", "event_type", "bill_date"
            )
        )

        patient_batch = []
        for p in patient_list:
            aid = p.get("AdmissionID", "")
            if aid in existing_patients:
                skipped_patients += 1
                continue

            patient_batch.append(
                HISTestPatient(
                    admission_id=aid,
                    patient_id=str(p.get("PatientID", "")),
                    patient_type=p.get("PatientType", ""),
                    reg_code=p.get("RegCode", ""),
                    ssn=p.get("SSN", ""),
                    mobile_no=p.get("MobileNo", ""),
                    admit_date=self._parse_date(p.get("AdmitDate")),
                    discharge_date=self._parse_date(p.get("DischargeDate")),
                    patient_data=p,
                    hospital_id=str(p.get("HospitalID", "")),
                    hospital_name=p.get("HospitalName", ""),
                    patient_name=p.get("PatientName", ""),
                )
            )

        if patient_batch:
            HISTestPatient.objects.bulk_create(patient_batch, batch_size=1000)
            patients_stored = len(patient_batch)

        visit_batch = []
        for v in ed_visits + ip_visits + op_visits:
            aid = v.get("AdmissionID", "")
            event_type = v.get("Type", "")
            bill_date = self._parse_date(v.get("BillDate"))
            visit_key = (aid, event_type, bill_date)
            if visit_key in existing_visits:
                continue

            visit_category = "ED"
            pt = v.get("PatientType", "")
            if pt == "IP":
                visit_category = "IP"
            elif pt in ("OP", "OPD"):
                visit_category = "OP"

            visit_batch.append(
                HISTestVisit(
                    admission_id=aid,
                    patient_id=str(v.get("PatientID", "")),
                    visit_category=visit_category,
                    event_type=event_type,
                    bill_date=bill_date,
                    reg_code=v.get("RegCode", ""),
                    ssn=v.get("SSN", ""),
                    mobile_no=v.get("MobileNo", ""),
                    visit_data=v,
                )
            )

        if visit_batch:
            HISTestVisit.objects.bulk_create(visit_batch, batch_size=2000)
            visits_stored = len(visit_batch)

        his_data = {
            "FetchPatientDataTimeStampList": patient_list,
            "FetchPatientDataTimeStampVisitEDDataList": ed_visits,
            "FetchPatientDataTimeStampVisitIPDataList": ip_visits,
            "FetchPatientDataTimeStampVisitOPDataList": op_visits,
            "Code": payload.get("Code", 200),
            "Status": payload.get("Status", "Success"),
            "Message": payload.get("Message", ""),
        }

        process_result = HISAdapter.process_his_response(his_data)

        return Response(
            {
                "storage": {
                    "patients_stored": patients_stored,
                    "patients_skipped": skipped_patients,
                    "visits_stored": visits_stored,
                },
                "processing": process_result,
            }
        )
