"""Patients API resource."""

from __future__ import annotations

from typing import TYPE_CHECKING

from medelement_mis.models import (
    CreatePatientRequest,
    CreatePatientResponse,
    Gender,
    PatientDetail,
    SearchPatientRequest,
    SearchPatientResponse,
    UpdatePatientRequest,
    UpdatePatientResponse,
)

if TYPE_CHECKING:
    from medelement_mis.client import MedelementClient


class PatientsAPI:
    """API resource for patient operations."""

    def __init__(self, client: MedelementClient) -> None:
        self._client = client

    def search(
        self,
        *,
        patient_code: list[int] | None = None,
        email: list[str] | None = None,
        name: str | None = None,
        lastname: str | None = None,
        middlename: str | None = None,
        gender: int | None = None,
        birthday: str | None = None,
        patient_phone_2: list[str] | None = None,
        skip: int | None = None,
        patient_status_code: int | None = None,
    ) -> SearchPatientResponse:
        """Search for patients.

        GET /doctor/v1/patients
        At least one search parameter is required.
        Returns max 100 records.

        Args:
            patient_code: Array of patient codes
            email: Array of email addresses
            name: First name filter
            lastname: Last name filter
            middlename: Middle name filter
            gender: Gender filter (1=Female, 2=Male)
            birthday: Birthday filter in dd.mm.yyyy format
            patient_phone_2: Phone as [country_code, city_code, phone]
            skip: Pagination offset
            patient_status_code: Patient status code filter

        Returns:
            SearchPatientResponse containing list of matching patients
        """
        request = SearchPatientRequest(
            patient_code=patient_code,
            email=email,
            name=name,
            lastname=lastname,
            middlename=middlename,
            gender=gender,
            birthday=birthday,
            patient_phone_2=patient_phone_2,
            skip=skip,
            patient_status_code=patient_status_code,
        )

        params = request.model_dump(exclude_none=True)

        response = self._client._request("GET", "/doctor/v1/patients", params=params)
        self._client._raise_for_status(response)

        payload = response.json()
        if payload == []:
            return SearchPatientResponse(root=[])

        return SearchPatientResponse.model_validate(payload)

    def search_v2(
        self,
        *,
        patient_code: list[int] | None = None,
        email: list[str] | None = None,
        iin: str | None = None,
        name: str | None = None,
        lastname: str | None = None,
        middlename: str | None = None,
        gender: int | None = None,
        birthday: str | None = None,
        patient_phone_2: list[str] | None = None,
        skip: int | None = None,
        patient_status_code: int | None = None,
    ) -> SearchPatientResponse:
        """Search for patients using v2 API.

        GET /doctor/v2/patients
        At least one search parameter with patient data is required.
        Returns max 100 records with pagination via skip.

        Args:
            patient_code: Array of unique patient codes
            email: Array of email addresses
            iin: Individual identification number
            name: First name filter
            lastname: Last name filter
            middlename: Middle name filter
            gender: Gender filter (1=Female, 2=Male)
            birthday: Birthday filter in dd.mm.yyyy format
            patient_phone_2: Phone as [country_code, city_code, phone]
            skip: Number of records to skip (pagination)
            patient_status_code: Patient status code filter

        Returns:
            SearchPatientResponse containing list of matching patients
        """
        request = SearchPatientRequest(
            patient_code=patient_code,
            email=email,
            name=name,
            lastname=lastname,
            middlename=middlename,
            gender=gender,
            birthday=birthday,
            patient_phone_2=patient_phone_2,
            skip=skip,
            patient_status_code=patient_status_code,
        )

        # Build params as list of tuples for proper array[] serialization
        params: list[tuple[str, str | int]] = []

        if patient_code:
            for code in patient_code:
                params.append(("patient_code[]", code))
        if email:
            for e in email:
                params.append(("email[]", e))
        if iin is not None:
            params.append(("iin", iin))

        simple_fields = request.model_dump(
            include={"name", "lastname", "middlename", "gender", "birthday", "skip", "patient_status_code"},
            exclude_none=True,
        )
        for key, value in simple_fields.items():
            params.append((key, value))

        if patient_phone_2:
            for i, part in enumerate(patient_phone_2):
                params.append((f"patient_phone_2[{i}]", part))

        response = self._client._request("GET", "/doctor/v2/patients", params=params)

        if not response.content or response.status_code == 404:
            return SearchPatientResponse(root=[])

        self._client._raise_for_status(response)

        payload = response.json()
        if payload == []:
            return SearchPatientResponse(root=[])

        return SearchPatientResponse.model_validate(payload)

    def get_by_iin(self, iin: str) -> SearchPatientResponse:
        """Get patients by IIN using the dedicated v2 endpoint.

        GET /doctor/v2/patients?iin=...

        Args:
            iin: Individual identification number

        Returns:
            SearchPatientResponse containing matching patients
        """
        response = self._client._request("GET", "/doctor/v2/patients", params={"iin": iin})
        self._client._raise_for_status(response)

        payload = response.json()
        if payload == []:
            return SearchPatientResponse(root=[])

        return SearchPatientResponse.model_validate(payload)

    def create(
        self,
        *,
        name: str,
        lastname: str,
        middlename: str | None = None,
        patient_email: str | None = None,
        birthday: str | None = None,
        gender: Gender | int | None = None,
        patient_phone_2: list[str] | None = None,
        iin: str | None = None,
        source_code: int | None = None,
        company_code: int | None = None,
    ) -> CreatePatientResponse:
        """Create a new patient.

        POST /doctor/v1/patient

        Args:
            name: Patient first name (required)
            lastname: Patient last name (required)
            middlename: Patient middle name
            patient_email: Patient email address
            birthday: Birthday in dd.mm.yyyy format
            gender: Gender (1=Female, 2=Male)
            patient_phone_2: Phone as [country_code, city_code, phone]
            iin: Individual identification number
            source_code: Information source code
            company_code: Company code for global API access

        Returns:
            CreatePatientResponse with profile_code
        """
        request = CreatePatientRequest(
            name=name,
            lastname=lastname,
            middlename=middlename,
            patient_email=patient_email,
            birthday=birthday,
            gender=gender,
            patient_phone_2=patient_phone_2,
            iin=iin,
            source_code=source_code,
            company_code=company_code,
        )

        response = self._client._request(
            "POST",
            "/doctor/v1/patient",
            json=request.model_dump(exclude_none=True),
        )
        self._client._raise_for_status(response)

        return CreatePatientResponse.model_validate(response.json())

    def get(self, patient_code: int) -> PatientDetail:
        """Get patient details by code.

        GET /doctor/v1/patient/:patient_code

        Args:
            patient_code: Patient's unique profile code

        Returns:
            PatientDetail with full patient information
        """
        response = self._client._request("GET", f"/doctor/v1/patient/{patient_code}")
        self._client._raise_for_status(response)

        return PatientDetail.model_validate(response.json())

    def update(
        self,
        *,
        profile_code: int,
        name: str | None = None,
        lastname: str | None = None,
        middlename: str | None = None,
        patient_email: str | None = None,
        birthday: str | None = None,
        gender: Gender | int | None = None,
        patient_phone_2: list[str] | None = None,
        iin: str | None = None,
        source_code: int | None = None,
        percentage_discount: int | None = None,
        social_status: int | None = None,
        benefit: int | None = None,
    ) -> UpdatePatientResponse:
        """Update an existing patient.

        PUT /doctor/v1/patient

        Args:
            profile_code: Patient profile code (required)
            name: Patient first name
            lastname: Patient last name
            middlename: Patient middle name
            patient_email: Patient email address
            birthday: Birthday in dd.mm.yyyy format
            gender: Gender (1=Female, 2=Male)
            patient_phone_2: Phone as [country_code, city_code, phone]
            iin: Individual identification number
            source_code: Information source code
            percentage_discount: Personal discount percent
            social_status: Social status code
            benefit: Concession/benefit code

        Returns:
            UpdatePatientResponse with updated patient data
        """
        request = UpdatePatientRequest(
            profile_code=profile_code,
            name=name,
            lastname=lastname,
            middlename=middlename,
            patient_email=patient_email,
            birthday=birthday,
            gender=gender,
            patient_phone_2=patient_phone_2,
            iin=iin,
            source_code=source_code,
            percentage_discount=percentage_discount,
            social_status=social_status,
            benefit=benefit,
        )

        response = self._client._request(
            "PUT",
            "/doctor/v1/patient",
            json=request.model_dump(exclude_none=True),
        )
        self._client._raise_for_status(response)

        return UpdatePatientResponse.model_validate(response.json())
