# -*- coding: utf-8 -*-
"""
Profile: http://hl7.org/fhir/StructureDefinition/Coverage
Release: R4
Version: 4.0.1
Build ID: 9346c8cc45
Last updated: 2019-11-01T09:29:23.356+11:00
"""
from typing import Any, Dict
from typing import List as ListType

from pydantic import Field, root_validator

from . import backboneelement, domainresource, fhirtypes


class Coverage(domainresource.DomainResource):
    """Disclaimer: Any field name ends with ``__ext`` does't part of
    Resource StructureDefinition, instead used to enable Extensibility feature
    for FHIR Primitive Data Types.

    Insurance or medical plan or a payment agreement.
    Financial instrument which may be used to reimburse or pay for health care
    products and services. Includes both insurance and self-payment.
    """

    resource_type = Field("Coverage", const=True)

    beneficiary: fhirtypes.ReferenceType = Field(
        ...,
        alias="beneficiary",
        title="Plan beneficiary",
        description=(
            "The party who benefits from the insurance coverage; the patient when "
            "products and/or services are provided."
        ),
        # note: Listed Resource Type(s) should be allowed as Reference.
        enum_reference_types=["Patient"],
    )

    class_fhir: ListType[fhirtypes.CoverageClassType] = Field(
        None,
        alias="class",
        title="Additional coverage classifications",
        description="A suite of underwriter specific classifiers.",
    )

    contract: ListType[fhirtypes.ReferenceType] = Field(
        None,
        alias="contract",
        title="Contract details",
        description="The policy(s) which constitute this insurance coverage.",
        # note: Listed Resource Type(s) should be allowed as Reference.
        enum_reference_types=["Contract"],
    )

    costToBeneficiary: ListType[fhirtypes.CoverageCostToBeneficiaryType] = Field(
        None,
        alias="costToBeneficiary",
        title="Patient payments for services/products",
        description=(
            "A suite of codes indicating the cost category and associated amount "
            "which have been detailed in the policy and may have been  included on "
            "the health card."
        ),
    )

    dependent: fhirtypes.String = Field(
        None,
        alias="dependent",
        title="Dependent number",
        description="A unique identifier for a dependent under the coverage.",
    )
    dependent__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
        None, alias="_dependent", title="Extension field for ``dependent``."
    )

    identifier: ListType[fhirtypes.IdentifierType] = Field(
        None,
        alias="identifier",
        title="Business Identifier for the coverage",
        description="A unique identifier assigned to this coverage.",
    )

    network: fhirtypes.String = Field(
        None,
        alias="network",
        title="Insurer network",
        description=(
            "The insurer-specific identifier for the insurer-defined network of "
            "providers to which the beneficiary may seek treatment which will be "
            "covered at the 'in-network' rate, otherwise 'out of network' terms and"
            " conditions apply."
        ),
    )
    network__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
        None, alias="_network", title="Extension field for ``network``."
    )

    order: fhirtypes.PositiveInt = Field(
        None,
        alias="order",
        title="Relative order of the coverage",
        description=(
            "The order of applicability of this coverage relative to other "
            "coverages which are currently in force. Note, there may be gaps in the"
            " numbering and this does not imply primary, secondary etc. as the "
            "specific positioning of coverages depends upon the episode of care."
        ),
    )
    order__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
        None, alias="_order", title="Extension field for ``order``."
    )

    payor: ListType[fhirtypes.ReferenceType] = Field(
        ...,
        alias="payor",
        title="Issuer of the policy",
        description=(
            "The program or plan underwriter or payor including both insurance and "
            "non-insurance agreements, such as patient-pay agreements."
        ),
        # note: Listed Resource Type(s) should be allowed as Reference.
        enum_reference_types=["Organization", "Patient", "RelatedPerson"],
    )

    period: fhirtypes.PeriodType = Field(
        None,
        alias="period",
        title="Coverage start and end dates",
        description=(
            "Time period during which the coverage is in force. A missing start "
            "date indicates the start date isn't known, a missing end date means "
            "the coverage is continuing to be in force."
        ),
    )

    policyHolder: fhirtypes.ReferenceType = Field(
        None,
        alias="policyHolder",
        title="Owner of the policy",
        description="The party who 'owns' the insurance policy.",
        # note: Listed Resource Type(s) should be allowed as Reference.
        enum_reference_types=["Patient", "RelatedPerson", "Organization"],
    )

    relationship: fhirtypes.CodeableConceptType = Field(
        None,
        alias="relationship",
        title="Beneficiary relationship to the subscriber",
        description="The relationship of beneficiary (patient) to the subscriber.",
    )

    status: fhirtypes.Code = Field(
        ...,
        alias="status",
        title="active | cancelled | draft | entered-in-error",
        description="The status of the resource instance.",
        # note: Enum values can be used in validation,
        # but use in your own responsibilities, read official FHIR documentation.
        enum_values=["active", "cancelled", "draft", "entered-in-error"],
    )
    status__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
        None, alias="_status", title="Extension field for ``status``."
    )

    subrogation: bool = Field(
        None,
        alias="subrogation",
        title="Reimbursement to insurer",
        description=(
            "When 'subrogation=true' this insurance instance has been included not "
            "for adjudication but to provide insurers with the details to recover "
            "costs."
        ),
    )
    subrogation__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
        None, alias="_subrogation", title="Extension field for ``subrogation``."
    )

    subscriber: fhirtypes.ReferenceType = Field(
        None,
        alias="subscriber",
        title="Subscriber to the policy",
        description=(
            "The party who has signed-up for or 'owns' the contractual relationship"
            " to the policy or to whom the benefit of the policy for services "
            "rendered to them or their family is due."
        ),
        # note: Listed Resource Type(s) should be allowed as Reference.
        enum_reference_types=["Patient", "RelatedPerson"],
    )

    subscriberId: fhirtypes.String = Field(
        None,
        alias="subscriberId",
        title="ID assigned to the subscriber",
        description="The insurer assigned ID for the Subscriber.",
    )
    subscriberId__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
        None, alias="_subscriberId", title="Extension field for ``subscriberId``."
    )

    type: fhirtypes.CodeableConceptType = Field(
        None,
        alias="type",
        title="Coverage category such as medical or accident",
        description=(
            "The type of coverage: social program, medical plan, accident coverage "
            "(workers compensation, auto), group health or payment by an individual"
            " or organization."
        ),
    )


class CoverageClass(backboneelement.BackboneElement):
    """Disclaimer: Any field name ends with ``__ext`` does't part of
    Resource StructureDefinition, instead used to enable Extensibility feature
    for FHIR Primitive Data Types.

    Additional coverage classifications.
    A suite of underwriter specific classifiers.
    """

    resource_type = Field("CoverageClass", const=True)

    name: fhirtypes.String = Field(
        None,
        alias="name",
        title="Human readable description of the type and value",
        description="A short description for the class.",
    )
    name__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
        None, alias="_name", title="Extension field for ``name``."
    )

    type: fhirtypes.CodeableConceptType = Field(
        ...,
        alias="type",
        title="Type of class such as 'group' or 'plan'",
        description=(
            "The type of classification for which an insurer-specific class label "
            "or number and optional name is provided, for example may be used to "
            "identify a class of coverage or employer group, Policy, Plan."
        ),
    )

    value: fhirtypes.String = Field(
        ...,
        alias="value",
        title="Value associated with the type",
        description=(
            "The alphanumeric string value associated with the insurer issued " "label."
        ),
    )
    value__ext: fhirtypes.FHIRPrimitiveExtensionType = Field(
        None, alias="_value", title="Extension field for ``value``."
    )


class CoverageCostToBeneficiary(backboneelement.BackboneElement):
    """Disclaimer: Any field name ends with ``__ext`` does't part of
    Resource StructureDefinition, instead used to enable Extensibility feature
    for FHIR Primitive Data Types.

    Patient payments for services/products.
    A suite of codes indicating the cost category and associated amount which
    have been detailed in the policy and may have been  included on the health
    card.
    """

    resource_type = Field("CoverageCostToBeneficiary", const=True)

    exception: ListType[fhirtypes.CoverageCostToBeneficiaryExceptionType] = Field(
        None,
        alias="exception",
        title="Exceptions for patient payments",
        description=(
            "A suite of codes indicating exceptions or reductions to patient costs "
            "and their effective periods."
        ),
    )

    type: fhirtypes.CodeableConceptType = Field(
        None,
        alias="type",
        title="Cost category",
        description="The category of patient centric costs associated with treatment.",
    )

    valueMoney: fhirtypes.MoneyType = Field(
        None,
        alias="valueMoney",
        title="The amount or percentage due from the beneficiary",
        description="The amount due from the patient for the cost category.",
        # Choice of Data Types. i.e value[x]
        one_of_many="value",
        one_of_many_required=True,
    )

    valueQuantity: fhirtypes.QuantityType = Field(
        None,
        alias="valueQuantity",
        title="The amount or percentage due from the beneficiary",
        description="The amount due from the patient for the cost category.",
        # Choice of Data Types. i.e value[x]
        one_of_many="value",
        one_of_many_required=True,
    )

    @root_validator(pre=True)
    def validate_one_of_many(cls, values: Dict[str, Any]) -> Dict[str, Any]:
        """https://www.hl7.org/fhir/formats.html#choice
        A few elements have a choice of more than one data type for their content.
        All such elements have a name that takes the form nnn[x].
        The "nnn" part of the name is constant, and the "[x]" is replaced with
        the title-cased name of the type that is actually used.
        The table view shows each of these names explicitly.

        Elements that have a choice of data type cannot repeat - they must have a
        maximum cardinality of 1. When constructing an instance of an element with a
        choice of types, the authoring system must create a single element with a
        data type chosen from among the list of permitted data types.
        """
        one_of_many_fields = {"value": ["valueMoney", "valueQuantity"]}
        for prefix, fields in one_of_many_fields.items():
            assert cls.__fields__[fields[0]].field_info.extra["one_of_many"] == prefix
            required = (
                cls.__fields__[fields[0]].field_info.extra["one_of_many_required"]
                is True
            )
            found = False
            for field in fields:
                if field in values and values[field] is not None:
                    if found is True:
                        raise ValueError(
                            "Any of one field value is expected from "
                            f"this list {fields}, but got multiple!"
                        )
                    else:
                        found = True
            if required is True and found is False:
                raise ValueError(f"Expect any of field value from this list {fields}.")

        return values


class CoverageCostToBeneficiaryException(backboneelement.BackboneElement):
    """Disclaimer: Any field name ends with ``__ext`` does't part of
    Resource StructureDefinition, instead used to enable Extensibility feature
    for FHIR Primitive Data Types.

    Exceptions for patient payments.
    A suite of codes indicating exceptions or reductions to patient costs and
    their effective periods.
    """

    resource_type = Field("CoverageCostToBeneficiaryException", const=True)

    period: fhirtypes.PeriodType = Field(
        None,
        alias="period",
        title="The effective period of the exception",
        description="The timeframe during when the exception is in force.",
    )

    type: fhirtypes.CodeableConceptType = Field(
        ...,
        alias="type",
        title="Exception category",
        description="The code for the specific exception.",
    )
