from couchforms.models import XFormInstance
import fluff
from corehq.fluff.calculators import xform as xcalculators
from fluff.filters import ANDFilter, NOTFilter
from casexml.apps.case.models import CommCareCase
from corehq.apps.fixtures.models import FixtureDataType, FixtureDataItem
from corehq.apps.groups.models import Group
from dimagi.utils.decorators.memoized import memoized
from couchdbkit.exceptions import ResourceNotFound

HCT_XMLNS = 'http://openrosa.org/formdesigner/BA7D3B3F-151C-4709-A020-CF79B7F2E876'
HBC_XMLNS = "http://openrosa.org/formdesigner/19A3BDCB-5EE6-4D1B-B64B-79361D7D9885"
PMM_XMLNS = "http://openrosa.org/formdesigner/d234f78e65e30eb72527c1118cf0de15e1181ddc"
IACT_XMLNS = "http://openrosa.org/formdesigner/BE27B9F4-A260-4110-B187-28D572B46DB0"
TB_XMLNS = "http://openrosa.org/formdesigner/9CB2E10D-18BE-4653-AE8F-A75958991D38"


class CareSAForm(XFormInstance):
    @property
    def user_id(self):
        return self.metadata.userID

    @property
    @memoized
    def gender(self):
        return self.care_case.gender.lower()

    @property
    @memoized
    def age_group(self):
        case = self.care_case

        try:
            if hasattr(case, 'patient_age'):
                age = int(case.patient_age)
            else:
                age = int(case.patients_age)
        except (AttributeError, ValueError):
            # catch fun things like no age being found or age not being
            # a number
            return '3'

        if age < 15:
            return '0'
        elif age < 25:
            return '1'
        else:
            return '2'

    @property
    @memoized
    def cbo(self):
        case = self.care_case

        group = Group.by_user(case.user_id).first()

        # if the id doesn't belong to a user, maybe its a group?
        if not group:
            try:
                group = Group.get(case.user_id)
            except ResourceNotFound:
                return None

        return group._id


    @property
    @memoized
    def province(self):
        case = self.care_case

        fixture_type = FixtureDataType.by_domain_tag('care-ihapc-live',
                                                     'province').first()

        fixture_item = FixtureDataItem.by_field_value(
            'care-ihapc-live',
            fixture_type,
            'id',
            case.province
        ).first()

        return fixture_item._id

    @property
    @memoized
    def care_case(self):
        return CommCareCase.get_by_xform_id(self._id).first()

class CareSAFluff(fluff.IndicatorDocument):
    document_class = XFormInstance
    wrapper = CareSAForm

    document_filter = ANDFilter([
        NOTFilter(xcalculators.FormPropertyFilter(xmlns='http://openrosa.org/user-registration')),
        NOTFilter(xcalculators.FormPropertyFilter(xmlns='http://openrosa.org/user/registration')),
        NOTFilter(xcalculators.FormPropertyFilter(xmlns='http://code.javarosa.org/devicereport')),
        xcalculators.CustomFilter(lambda f: f.gender in ['male', 'female']),
        xcalculators.CustomFilter(lambda f: f.cbo),
    ])


    domains = ('care-ihapc-live',)
    group_by = (
        'domain',
        'user_id',
        'province',
        'cbo',
        'age_group',
        'gender',
    )


    # Report 1
    # Testing and Counseling

    #1a
    # tested
    hiv_counseling = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/testing_consent',
        property_value='counseling_testing',
    )

    #1b
    hiv_tested = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/hiv_tested',
        property_value='yes',
    )

    #1c
    # no results
    internal_hiv_pos_test = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/test_results',
        property_value='hiv_pos',
    )
    hiv_positive = xcalculators.and_calc(
        [hiv_tested, internal_hiv_pos_test]
    )

    #1d
    new_hiv_tb_screen = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/test_results',
        operator=xcalculators.ANY,
    )

    #1ea
    tb_screened = xcalculators.filtered_form_calc(
        xmlns=TB_XMLNS,
        property_path='form/tb_screening',
        operator=xcalculators.ANY,
    )

    #1eb
    internal_tb_screening_any = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/tb_screening',
        operator=xcalculators.ANY,
    )
    internal_testing_counseling = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/testing_consent',
        property_value='only_counseling',
    )
    internal_testing_referral = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/testing_consent',
        property_value='only_referral',
    )
    internal_testing_answers = xcalculators.or_calc(
        [internal_testing_counseling, internal_testing_referral]
    )
    hct_screened = xcalculators.and_calc(
        [internal_tb_screening_any, internal_testing_answers]
    )

    #1f
    referred_tb_signs = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/refer_phcf_tb',
        property_value='yes',
    )

    #1g TODO NOT IN FORM

    #1h
    internal_refer_phcf = xcalculators.filtered_form_calc(
        xmlns=HCT_XMLNS,
        property_path='form/refer_phcf',
        property_value='yes',
    )