# SPDX-FileCopyrightText: 2008-2025 Luis Falcón <falcon@gnuhealth.org>
# SPDX-FileCopyrightText: 2011-2025 GNU Solidario <health@gnusolidario.org>
#
# SPDX-License-Identifier: GPL-3.0-or-later

#########################################################################
#   Hospital Management Information System (HMIS) component of the      #
#                       GNU Health project                              #
#                   https://www.gnuhealth.org                           #
#########################################################################
#                       HEALTH DISABILITY package                       #
#                   health_disability.py: main module                   #
#########################################################################
# THIS PACKAGE APPLIES SOME CONCEPTS FROMTHE WORLD HEALTH ORGANIZATION  #
# INTERNATIONAL CLASSIFICATION OF FUNCTIONING, DISABILITY AND HEALTH    #
#         REFER TO THE DOCUMENTATION FOR FURTHER INFORMATION            #
#########################################################################

from datetime import date
from trytond.model import ModelView, ModelSQL, fields, Unique
from trytond.modules.health.core import get_health_professional

__all__ = ['GnuHealthPatient',
           'Product', 'BodyFunctionCategory', 'BodyFunction',
           'BodyStructureCategory', 'BodyStructure',
           'ActivityAndParticipationCategory', 'ActivityAndParticipation',
           'EnvironmentalFactorCategory', 'EnvironmentalFactor',
           'PatientDisabilityAssessment',
           'PatientBodyFunctionAssessment',
           'PatientBodyStructureAssessment',
           'PatientActivityAndParticipationAsssessment',
           'PatientEnvironmentalFactorAssessment',
           'PatientAmputation', 'PatientProthesis',
           'PatientData']


# Include disabilty amputation and UXO casualty information on patient model
class GnuHealthPatient(ModelSQL, ModelView):
    __name__ = 'gnuhealth.patient'

    disability = fields.Boolean(
        'Disabilities / Barriers', help="Mark this "
        "box if the patient has history of significant disabilities and/or "
        "barriers. Review the Disability Assessments, socioeconomic info,  "
        "diseases and surgeries for more details")
    uxo = fields.Boolean('UXO', help="UXO casualty")
    amputee = fields.Boolean(
        'Amputee', help="Person has had one or more"
        " limbs removed by amputation. Includes congenital conditions")
    amputee_since = fields.Date('Since', help="Date of amputee status")

    amputations = fields.One2Many(
        'gnuhealth.patient.amputation', 'patient', 'Amputations')

    protheses = fields.One2Many(
        'gnuhealth.patient.prothesis', 'patient', 'Protheses')


class Product(ModelSQL, ModelView):
    'Product'
    __name__ = 'product.product'

    is_prothesis = fields.Boolean(
        'Prothesis', help='Check if the product is a prothesis')


class BodyFunctionCategory(ModelSQL, ModelView):
    'Body Function Category'
    __name__ = 'gnuhealth.body_function.category'

    name = fields.Char('Name', required=True, translate=True)
    code = fields.Char('code', required=True)

    @classmethod
    def __setup__(cls):
        super(BodyFunctionCategory, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t, t.code),
                'The code must be unique !'),
        ]


class BodyFunction(ModelSQL, ModelView):
    'Body Functions'
    __name__ = 'gnuhealth.body_function'

    name = fields.Char('Function', required=True, translate=True)
    code = fields.Char('code', required=True)
    category = fields.Many2One('gnuhealth.body_function.category', 'Category')

    @classmethod
    def __setup__(cls):
        super(BodyFunction, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t, t.code),
                'The code must be unique !'),
        ]


class BodyStructureCategory(ModelSQL, ModelView):
    'Body Structure Category'
    __name__ = 'gnuhealth.body_structure.category'

    name = fields.Char('Name', required=True, translate=True)
    code = fields.Char('code', required=True)

    @classmethod
    def __setup__(cls):
        super(BodyStructureCategory, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t, t.code),
                'The code must be unique !'),
        ]


class BodyStructure(ModelSQL, ModelView):
    'Body Functions'
    __name__ = 'gnuhealth.body_structure'

    name = fields.Char('Structure', required=True, translate=True)
    code = fields.Char('code', required=True)
    category = fields.Many2One('gnuhealth.body_structure.category', 'Category')

    @classmethod
    def __setup__(cls):
        super(BodyStructure, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t, t.code),
                'The code must be unique !'),
        ]


class ActivityAndParticipationCategory(ModelSQL, ModelView):
    'Activity and Participation Category'
    __name__ = 'gnuhealth.activity_and_participation.category'

    name = fields.Char('Name', required=True, translate=True)
    code = fields.Char('code', required=True)

    @classmethod
    def __setup__(cls):
        super(ActivityAndParticipationCategory, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t, t.code),
                'The code must be unique !'),
        ]


class ActivityAndParticipation(ModelSQL, ModelView):
    'Activity limitations and participation restrictions'
    __name__ = 'gnuhealth.activity_and_participation'

    name = fields.Char('A & P', required=True, translate=True)
    code = fields.Char('code', required=True)
    category = fields.Many2One(
        'gnuhealth.activity_and_participation.category', 'Category')

    @classmethod
    def __setup__(cls):
        super(ActivityAndParticipation, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t, t.code),
                'The code must be unique !'),
        ]


class EnvironmentalFactorCategory(ModelSQL, ModelView):
    'Environmental Factor Category'
    __name__ = 'gnuhealth.environmental_factor.category'

    name = fields.Char('Name', required=True, translate=True)
    code = fields.Char('code', required=True)

    @classmethod
    def __setup__(cls):
        super(EnvironmentalFactorCategory, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t, t.code),
                'The code must be unique !'),
        ]


class EnvironmentalFactor(ModelSQL, ModelView):
    'Environmental factors restrictions'
    __name__ = 'gnuhealth.environmental_factor'

    name = fields.Char('Environment', required=True, translate=True)
    code = fields.Char('code', required=True)
    category = fields.Many2One(
        'gnuhealth.environmental_factor.category', 'Category')

    @classmethod
    def __setup__(cls):
        super(EnvironmentalFactor, cls).__setup__()
        t = cls.__table__()
        cls._sql_constraints = [
            ('code_uniq', Unique(t, t.code),
                'The code must be unique !'),
        ]


class PatientDisabilityAssessment(ModelSQL, ModelView):
    'Patient Disability Information'
    __name__ = 'gnuhealth.patient.disability_assessment'

    patient = fields.Many2One('gnuhealth.patient', 'Patient', required=True)

    assessment_date = fields.Date('Date')

    assessment = fields.Char('Code')

    crutches = fields.Boolean('Crutches')
    wheelchair = fields.Boolean('Wheelchair')

    uxo = fields.Function(fields.Boolean('UXO'), 'get_uxo_status')
    amputee = fields.Function(
        fields.Boolean('Amputee'),
        'get_amputee_status')
    amputee_since = fields.Function(
        fields.Date('Since'),
        'get_amputee_date')

    notes = fields.Text('Notes', help="Extra Information")

    hand_function = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Moderate impairment'),
        ('3', 'Severe impairment'),
        ('4', 'Complete impairment'),
    ], 'Hand', sort=False)

    visual_function = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Moderate impairment'),
        ('3', 'Severe impairment'),
        ('4', 'Complete impairment'),
    ], 'Visual', sort=False)

    speech_function = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Moderate impairment'),
        ('3', 'Severe impairment'),
        ('4', 'Complete impairment'),
    ], 'Speech', sort=False)

    hearing_function = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Moderate impairment'),
        ('3', 'Severe impairment'),
        ('4', 'Complete impairment'),
    ], 'Hearing', sort=False)

    cognitive_function = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Moderate impairment'),
        ('3', 'Severe impairment'),
        ('4', 'Complete impairment'),
    ], 'Cognitive', sort=False)

    locomotor_function = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Moderate impairment'),
        ('3', 'Severe impairment'),
        ('4', 'Complete impairment'),
    ], 'Mobility', sort=False)

    activity_participation = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Moderate impairment'),
        ('3', 'Severe impairment'),
        ('4', 'Complete impairment'),
    ], 'A & P', sort=False)

    body_functions = fields.One2Many(
        'gnuhealth.body_function.assessment',
        'assessment', 'Body Functions Impairments')

    body_structures = fields.One2Many(
        'gnuhealth.body_structure.assessment',
        'assessment', 'Body Structures Impairments')

    activity_and_participation = fields.One2Many(
        'gnuhealth.activity.assessment',
        'assessment',
        'Activities and Participation Impairments')

    environmental_factor = fields.One2Many(
        'gnuhealth.environment.assessment',
        'assessment',
        'Environmental Factors Barriers')

    healthprof = fields.Many2One(
        'gnuhealth.healthprofessional', 'Health Prof',
        help="Authorized health professional")

    def get_uxo_status(self, name):
        return self.patient.uxo

    def get_amputee_status(self, name):
        return self.patient.amputee

    def get_amputee_date(self, name):
        return self.patient.amputee_since

    @staticmethod
    def default_assessment_date():
        return date.today()

    @staticmethod
    def default_healthprof():
        return get_health_professional()


class PatientBodyFunctionAssessment(ModelSQL, ModelView):
    'Body Functions Assessment'
    __name__ = 'gnuhealth.body_function.assessment'

    assessment = fields.Many2One(
        'gnuhealth.patient.disability_assessment',
        'Assessment', required=True)
    body_function = fields.Many2One('gnuhealth.body_function', 'Body Function')
    qualifier = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Severe impairment'),
        ('3', 'Complete impairment'),
        ('8', 'Not specified'),
        ('9', 'Not applicable'),
    ], 'Qualifier', sort=False)


class PatientBodyStructureAssessment(ModelSQL, ModelView):
    'Body Functions Assessment'
    __name__ = 'gnuhealth.body_structure.assessment'

    assessment = fields.Many2One(
        'gnuhealth.patient.disability_assessment',
        'Assessment', required=True)
    body_structure = fields.Many2One(
        'gnuhealth.body_structure', 'Body Structure')
    qualifier1 = fields.Selection([
        (None, ''),
        ('0', 'No impairment'),
        ('1', 'Mild impairment'),
        ('2', 'Moderate impairment'),
        ('3', 'Severe impairment'),
        ('4', 'Complete impairment'),
        ('8', 'Not specified'),
        ('9', 'Not applicable'),
    ], 'Extent', help="Extent of the impairment", sort=False)

    qualifier2 = fields.Selection([
        (None, ''),
        ('0', 'No change in structure'),
        ('1', 'Total absence'),
        ('2', 'Partial absence'),
        ('3', 'Additional part'),
        ('4', 'Aberrant dimensions'),
        ('5', 'Discontinuity'),
        ('6', 'Deviating position'),
        ('7', 'Qualitative changes in structure,'
            ' including accumulation of fluid'),
        ('8', '8 - Not specified'),
        ('9', '9 - Not applicable'),
    ], 'Nature', help="Nature of the change", sort=False)

    body_side = fields.Selection([
        (None, ''),
        ('left', 'Left'),
        ('right', 'Right'),
        ('both', 'Both'),
    ], 'Side', help="Side of the body, if applies", sort=False)


class PatientActivityAndParticipationAsssessment(ModelSQL, ModelView):
    'Activity and Participation Assessment'
    __name__ = 'gnuhealth.activity.assessment'

    assessment = fields.Many2One(
        'gnuhealth.patient.disability_assessment',
        'Assessment', required=True)

    activity_and_participation = fields.Many2One(
        'gnuhealth.activity_and_participation', 'Activity')

    qualifier1 = fields.Selection([
        (None, ''),
        ('0', 'No difficulty'),
        ('1', 'Mild difficulty'),
        ('2', 'Moderate difficulty'),
        ('3', 'Severe difficulty'),
        ('4', 'Complete difficulty'),
        ('8', 'Not specified'),
        ('9', 'Not applicable'),
    ], 'Performance', help="Extent of the difficulty", sort=False)

    qualifier2 = fields.Selection([
        (None, ''),
        ('0', 'No difficulty'),
        ('1', 'Mild difficulty'),
        ('2', 'Moderate difficulty'),
        ('3', 'Severe difficulty'),
        ('4', 'Complete difficulty'),
        ('8', 'Not specified'),
        ('9', 'Not applicable'),
    ], 'Capacity', help="Extent of the dificulty", sort=False)


class PatientEnvironmentalFactorAssessment(ModelSQL, ModelView):
    'Environmental Factors Assessment'
    __name__ = 'gnuhealth.environment.assessment'

    assessment = fields.Many2One(
        'gnuhealth.patient.disability_assessment',
        'Assessment', required=True)

    environmental_factor = fields.Many2One(
        'gnuhealth.environmental_factor', 'Environment')

    qualifier = fields.Selection([
        (None, ''),
        ('0', 'No barriers'),
        ('1', 'Mild barriers'),
        ('2', 'Moderate barriers'),
        ('3', 'Severe barriers'),
        ('4', 'Complete barriers'),
        ('00', 'No facilitator'),
        ('11', 'Mild facilitator'),
        ('22', 'Moderate facilitator'),
        ('33', 'Severe facilitator'),
        ('44', 'Complete facilitator'),
    ], 'Barriers',
        help="Extent of the barriers or facilitators", sort=False)


# Amputation Information
class PatientAmputation(ModelSQL, ModelView):
    'Amputation'
    __name__ = 'gnuhealth.patient.amputation'

    patient = fields.Many2One('gnuhealth.patient', 'Patient', required=True)

    amputation_date = fields.Date('Date')

    body_structure = fields.Many2One('gnuhealth.body_structure', 'Structure')

    etiology = fields.Selection([
        (None, ''),
        ('pvd', 'Peripherial Vascular Disease'),
        ('trauma', 'Trauma'),
        ('neoplasia', 'Neoplasia'),
        ('infection', 'Infection'),
        ('congenital', 'Congenital'),
    ], 'Etiology', sort=False)

    limb = fields.Selection([
        (None, ''),
        ('lower', 'lower limb'),
        ('upper', 'upper limb'),
    ], 'Limb', sort=False)

    side = fields.Selection([
        (None, ''),
        ('left', 'left'),
        ('right', 'right'),
        ('both', 'both'),
    ], 'Side', sort=False)

    amputation_level = fields.Selection([
        (None, ''),
        ('sd', 'SD - Shoulder disarticulation'),
        ('th', 'TH - Transhumeral'),
        ('ed', 'ED - Elbow disarticulation'),
        ('tr', 'TR - Transradial'),
        ('wd', 'WD - Wrist disarticulation'),
        ('ph', 'PH'),
        ('hp', 'HD - Hemipelvectomy'),
        ('tf', 'TF - Transfemoral'),
        ('tt', 'TT - Transtibial'),
        ('symes', 'Symes'),
        ('pffd', 'PFFD'),
    ], 'Level', sort=False)

    comments = fields.Char('Comments')

    healthprof = fields.Many2One(
        'gnuhealth.healthprofessional', 'Health Prof',
        help="Authorized health professional")

    @staticmethod
    def default_healthprof():
        return get_health_professional()


# Patient Protheses Information
class PatientProthesis(ModelSQL, ModelView):
    'Prothesis'
    __name__ = 'gnuhealth.patient.prothesis'

    patient = fields.Many2One('gnuhealth.patient', 'Patient', required=True)

    issue_date = fields.Date('Date')

    prothesis = fields.Many2One(
        'product.product', 'Prothesis', required=True,
        domain=[('is_prothesis', '=', True)],
        help='Prosthetic device')

    comments = fields.Char('Comments')

    healthprof = fields.Many2One(
        'gnuhealth.healthprofessional', 'Health Prof',
        help="Prosthetist or authorized health professional")

    @staticmethod
    def default_healthprof():
        return get_health_professional()


class PatientData (ModelSQL, ModelView):
    __name__ = 'gnuhealth.patient'

    disability_assesments = fields.One2Many(
        'gnuhealth.patient.disability_assessment',
        'patient', 'Assessment', readonly=True)
