"""
HIS Client Service - Fetches patient data from external HIS systems

This service provides a client to fetch patient survey data from
Hospital Information Systems (HIS) via their APIs.
"""

import logging
import os
from datetime import datetime, timedelta
from typing import Dict, List, Optional
from urllib.parse import quote

import requests
from django.utils import timezone

from apps.integrations.models import IntegrationConfig, SourceSystem

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


class HISClient:
    """
    Client for fetching patient data from HIS systems.

    This client connects to external HIS APIs and retrieves
    patient demographic and visit data for survey processing.
    """

    def __init__(self, config: Optional[IntegrationConfig] = None):
        """
        Initialize HIS client.

        Args:
            config: IntegrationConfig instance (optional).
                   Environment variables (.env) take priority.
        """
        from django.conf import settings

        self.config = config
        self.session = requests.Session()

        # Load credentials from Django settings (which reads .env)
        self.username = getattr(settings, "HIS_API_USERNAME", "")
        self.password = getattr(settings, "HIS_API_PASSWORD", "")

    def _get_default_config(self) -> Optional[IntegrationConfig]:
        """Get default active HIS configuration from database."""
        try:
            return IntegrationConfig.objects.filter(source_system=SourceSystem.HIS, is_active=True).first()
        except Exception as e:
            logger.error(f"Error loading HIS configuration: {e}")
            return None

    def _get_headers(self) -> Dict[str, str]:
        """Get request headers with authentication."""
        from django.conf import settings

        headers = {
            "Content-Type": "application/json",
            "Accept": "application/json",
        }

        # Priority 1: API key from Django settings
        api_key = getattr(settings, "HIS_API_KEY", None)
        if api_key:
            headers["X-API-Key"] = api_key
            headers["Authorization"] = f"Bearer {api_key}"
        # Priority 2: API key from database config (if passed)
        elif self.config and self.config.api_key:
            headers["X-API-Key"] = self.config.api_key
            headers["Authorization"] = f"Bearer {self.config.api_key}"

        return headers

    def _get_api_url(self) -> Optional[str]:
        """Get API URL from Django settings (priority) or fallback."""
        from django.conf import settings

        # Priority 1: Django settings (.env file)
        settings_url = getattr(settings, "HIS_API_URL", None)
        if settings_url:
            return settings_url

        # Priority 2: Database config (if explicitly passed)
        if self.config and self.config.api_url:
            return self.config.api_url

        # Priority 3: Hardcoded default
        return "https://his.alhammadi.med.sa/SSRCE/API/FetchPatientVisitTimeStamps"

    def _get_auth(self) -> Optional[tuple]:
        """Get Basic Auth credentials."""
        if self.username and self.password:
            return (self.username, self.password)
        return None

    def fetch_patient_data(self, since: Optional[datetime] = None, until: Optional[datetime] = None) -> Optional[Dict]:
        """
        Fetch full patient data from HIS system including visit timelines.

        Returns the complete HIS response dict with all arrays intact:
        - FetchPatientDataTimeStampList
        - FetchPatientDataTimeStampVisitEDDataList
        - FetchPatientDataTimeStampVisitIPDataList
        - FetchPatientDataTimeStampVisitOPDataList

        Args:
            since: Only fetch patients since this datetime
            until: Only fetch patients until this datetime (optional)

        Returns:
            Full HIS response dict or None if error
        """
        api_url = self._get_api_url()
        if not api_url:
            logger.error("No HIS API URL configured")
            return None

        try:
            if since:
                end_time = until if until else timezone.now()
            else:
                end_time = timezone.now()
                since = end_time - timedelta(minutes=5)

            from_date = self._format_datetime(since)
            to_date = self._format_datetime(end_time)

            url = f"{api_url}?FromDate={quote(from_date)}&ToDate={quote(to_date)}&SSN=0&MobileNo=0"

            logger.info(f"Fetching patient data from HIS: {url}")

            response = self.session.get(
                url,
                headers=self._get_headers(),
                auth=self._get_auth(),
                timeout=30,
                verify=True,
            )
            response.raise_for_status()

            data = response.json()

            if isinstance(data, dict):
                patient_count = len(data.get("FetchPatientDataTimeStampList", []))
                logger.info(f"Fetched {patient_count} patients from HIS")
                return data
            else:
                logger.error(f"Unexpected HIS response type: {type(data)}")
                return None

        except requests.exceptions.RequestException as e:
            logger.error(f"Error fetching patient data from HIS: {e}")
            return None
        except Exception as e:
            logger.error(f"Unexpected error fetching patient data from HIS: {e}")
            return None

    def fetch_doctor_ratings(self, from_date: datetime, to_date: datetime) -> Optional[Dict]:
        """
        Fetch doctor ratings from HIS FetchDoctorRatingMAPI endpoint.

        Args:
            from_date: Start date for ratings
            to_date: End date for ratings

        Returns:
            HIS response dict with FetchDoctorRatingMAPIList or None on error
        """
        from django.conf import settings

        api_url = getattr(settings, "HIS_RATINGS_API_URL", None)
        if not api_url:
            logger.error("HIS_RATINGS_API_URL not configured in Django settings")
            return None

        try:
            from_date_str = self._format_datetime(from_date)
            to_date_str = self._format_datetime(to_date)

            url = f"{api_url}?FromDate={quote(from_date_str)}&ToDate={quote(to_date_str)}&SSN=0&MobileNo=0"

            logger.info(f"Fetching doctor ratings from HIS: {url}")

            response = self.session.get(
                url,
                headers=self._get_headers(),
                auth=self._get_auth(),
                timeout=30,
                verify=True,
            )
            response.raise_for_status()

            logger.info(f"HIS doctor ratings response status: {response.status_code}")
            logger.debug(f"HIS doctor ratings response body: {response.text[:2000]}")

            data = response.json()

            if isinstance(data, dict):
                logger.info(f"HIS doctor ratings response keys: {list(data.keys())}")
                rating_count = len(data.get("FetchDoctorRatingMAPI1List", []))
                logger.info(f"Fetched {rating_count} doctor ratings from HIS")
                if rating_count == 0 and data:
                    logger.info(f"Full HIS response (no ratings): {data}")
                return data
            else:
                logger.error(f"Unexpected HIS response type: {type(data)}")
                return None

        except requests.exceptions.RequestException as e:
            logger.error(f"Error fetching doctor ratings from HIS: {e}")
            return None
        except Exception as e:
            logger.error(f"Unexpected error fetching doctor ratings from HIS: {e}")
            return None

    def fetch_patient_by_identifier(self, ssn: Optional[str] = None, mobile_no: Optional[str] = None) -> Optional[Dict]:
        """
        Search HIS for a patient by SSN or Mobile number.

        Uses a wide date range (5 years) since we are searching by
        identifier rather than date. Returns only the patient
        demographics list from the HIS response.

        Args:
            ssn: Patient SSN/National ID
            mobile_no: Patient mobile number

        Returns:
            List of patient demographic dicts from HIS, or None on error
        """
        if not ssn and not mobile_no:
            logger.warning("fetch_patient_by_identifier called without SSN or MobileNo")
            return None

        api_url = self._get_api_url()
        if not api_url:
            logger.error("No HIS API URL configured")
            return None

        try:
            end_time = timezone.now()
            since = end_time - timedelta(days=365 * 5)

            from_date = self._format_datetime(since)
            to_date = self._format_datetime(end_time)
            ssn_param = ssn or "0"
            mobile_param = mobile_no or "0"

            url = (
                f"{api_url}?FromDate={quote(from_date)}&ToDate={quote(to_date)}"
                f"&SSN={quote(ssn_param)}&MobileNo={quote(mobile_param)}"
            )

            logger.info(f"Searching HIS by identifier: SSN={ssn_param}, Mobile={mobile_param}")

            response = self.session.get(
                url,
                headers=self._get_headers(),
                auth=self._get_auth(),
                timeout=30,
                verify=True,
            )
            response.raise_for_status()

            data = response.json()

            if isinstance(data, dict):
                patients = data.get("FetchPatientDataTimeStampList", [])
                logger.info(f"HIS identifier search returned {len(patients)} patients")
                return patients
            else:
                logger.error(f"Unexpected HIS response type: {type(data)}")
                return None

        except requests.exceptions.RequestException as e:
            logger.error(f"Error searching HIS by identifier: {e}")
            return None
        except Exception as e:
            logger.error(f"Unexpected error searching HIS by identifier: {e}")
            return None

    def fetch_patient_visits(self, patient_id: str) -> List[Dict]:
        """
        Fetch visit data for a specific patient.

        Args:
            patient_id: Patient ID from HIS

        Returns:
            List of visit data dictionaries
        """
        api_url = self._get_api_url()
        if not api_url:
            return []

        visits_endpoint = f"{api_url.rstrip('/')}/{patient_id}/visits"

        try:
            response = self.session.get(visits_endpoint, headers=self._get_headers(), timeout=30)
            response.raise_for_status()

            data = response.json()

            if isinstance(data, list):
                return data
            elif isinstance(data, dict):
                return data.get("FetchPatientDataTimeStampVisitDataList", [])
            return []

        except requests.exceptions.RequestException as e:
            logger.error(f"Error fetching visits for patient {patient_id}: {e}")
            return []

    def test_connection(self) -> Dict:
        """
        Test connectivity to HIS system.

        Returns:
            Dict with 'success' boolean and 'message' string
        """
        api_url = self._get_api_url()
        if not api_url:
            return {"success": False, "message": "No API URL configured"}

        try:
            # Try to fetch patients for last 1 minute as a test
            end_time = timezone.now()
            start_time = end_time - timedelta(minutes=1)

            from_date = self._format_datetime(start_time)
            to_date = self._format_datetime(end_time)

            url = f"{api_url}?FromDate={quote(from_date)}&ToDate={quote(to_date)}&SSN=0&MobileNo=0"

            response = self.session.get(
                url, headers=self._get_headers(), auth=self._get_auth(), timeout=10, verify=True
            )

            if response.status_code == 200:
                return {
                    "success": True,
                    "message": "Successfully connected to HIS",
                    "config_name": self.config.name if self.config else "Default",
                }
            else:
                return {"success": False, "message": f"HIS returned status {response.status_code}"}

        except requests.exceptions.ConnectionError:
            return {"success": False, "message": "Could not connect to HIS server"}
        except requests.exceptions.Timeout:
            return {"success": False, "message": "Connection to HIS timed out"}
        except Exception as e:
            return {"success": False, "message": f"Error: {str(e)}"}

    @staticmethod
    def _format_datetime(dt: datetime) -> str:
        """Format datetime for HIS API (DD-Mon-YYYY HH:MM:SS format)."""
        months = ["Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
        return f"{dt.day:02d}-{months[dt.month - 1]}-{dt.year} {dt.hour:02d}:{dt.minute:02d}:{dt.second:02d}"


class HISClientFactory:
    """Factory for creating HIS clients."""

    @staticmethod
    def get_client(hospital_id: Optional[str] = None) -> HISClient:
        """
        Get HIS client for a specific hospital or default.

        Args:
            hospital_id: Optional hospital ID to get specific config

        Returns:
            HISClient instance
        """
        config = None

        if hospital_id:
            # Try to find config for specific hospital
            try:
                from apps.organizations.models import Hospital

                hospital = Hospital.objects.filter(id=hospital_id).first()
                if hospital:
                    config = IntegrationConfig.objects.filter(
                        source_system=SourceSystem.HIS, is_active=True, config_json__hospital_id=str(hospital.id)
                    ).first()
            except Exception:
                pass

        return HISClient(config)

    @staticmethod
    def get_all_active_clients() -> List[HISClient]:
        """Get all active HIS clients for multi-hospital setups."""
        from django.conf import settings

        # Priority 1: If Django settings has HIS API URL, use it
        if getattr(settings, "HIS_API_URL", None):
            logger.info("Using HIS API URL from Django settings (.env file)")
            return [HISClient()]

        # Priority 2: Fall back to database configs (for multi-hospital setups)
        configs = IntegrationConfig.objects.filter(source_system=SourceSystem.HIS, is_active=True)

        if not configs.exists():
            # Return default client with no config
            logger.warning("No HIS API URL configured in settings or database")
            return [HISClient()]

        logger.info(f"Found {configs.count()} HIS configuration(s) in database")
        return [HISClient(config) for config in configs]
