#!/usr/bin/env python

# 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 LIFESTYLE package                           #
#                 health_lifestyle.py: main module                      #
#########################################################################
from trytond.model import ModelView, ModelSQL, fields, Unique
from datetime import datetime
from trytond.pool import PoolMeta

__all__ = ['VegetarianTypes', 'DietBelief', 'DrugsRecreational',
           'PatientRecreationalDrugs', 'PatientCAGE', 'MedicalPatient']


class VegetarianTypes(ModelSQL, ModelView):
    'Vegetarian Types'
    __name__ = 'gnuhealth.vegetarian_types'

    name = fields.Char(
        'Vegetarian', translate=True, required=True,
        help="Vegetarian")
    code = fields.Char(
        'Code', required=True,
        help="Short description")
    desc = fields.Char(
        'Description', translate=True, required=True,
        help="Short description")


# Diet by belief / religion
class DietBelief (ModelSQL, ModelView):
    'Diet by Belief'
    __name__ = "gnuhealth.diet.belief"

    name = fields.Char('Belief', required=True, translate=True)
    code = fields.Char('Code', required=True)
    description = fields.Text('Description', required=True, translate=True)

    @classmethod
    def __setup__(cls):
        super(DietBelief, cls).__setup__()

        t = cls.__table__()
        cls._sql_constraints = [
            ('code_unique', Unique(t, t.code),
                'The Diet code already exists'),
        ]


class DrugsRecreational(ModelSQL, ModelView):
    'Recreational Drug'
    __name__ = 'gnuhealth.drugs_recreational'

    name = fields.Char(
        'Name', translate=True, required=True,
        help="Name of the drug")
    code = fields.Char(
        'Code', required=True,
        help="Please use CAPITAL LETTERS and no spaces")
    street_name = fields.Char(
        'Street names',
        help="Common name of the drug in street jargon")

    toxicity = fields.Selection([
        (None, ''),
        ('0', 'None'),
        ('1', 'Low'),
        ('2', 'High'),
        ('3', 'Extreme'),
    ], 'Toxicity', sort=False)

    addiction_level = fields.Selection([
        (None, ''),
        ('0', 'None'),
        ('1', 'Low'),
        ('2', 'High'),
        ('3', 'Extreme'),
    ], 'Dependence', sort=False)

    legal_status = fields.Selection([
        (None, ''),
        ('0', 'Legal'),
        ('1', 'Illegal'),
    ], 'Legal Status', sort=False)

    category = fields.Selection([
        (None, ''),
        ('cannabinoid', 'Cannabinoids'),
        ('depressant', 'Depressants'),
        ('dissociative', 'Dissociative Anesthetics'),
        ('hallucinogen', 'Hallucinogens'),
        ('opioid', 'Opioids'),
        ('stimulant', 'Stimulants'),
        ('other', 'Others'),
    ], 'Category', sort=False)

    withdrawal_level = fields.Integer(
        'Withdrawal',
        help="Presence and severity of characteristic withdrawal "
        "symptoms.\nUsing Henningfield rating. 1=highest and 6=lowest")

    reinforcement_level = fields.Integer(
        'Reinforcement',
        help="A measure of the substance's ability to get users to take it "
        " again and again, and in preference to other substances.\nUsing "
        " Henningfield rating. 1=highest and 6=lowest")

    tolerance_level = fields.Integer(
        'Tolerance',
        help="How much of the substance is needed to satisfy increasing "
        "cravings for it, and the level of stable need that is eventually "
        "reached.\nUsing Henningfield rating. 1=highest and 6=lowest")

    dependence_level = fields.Integer(
        'Dependence',
        help="How difficult it is for the user to quit, the relapse rate, "
        "the percentage of people who eventually become dependent, the "
        "rating users give their own need for the substance and the "
        "degree to which the substance will be used in the face of "
        "evidence that it causes harm.\nUsing Henningfield rating. "
        "1=highest and 6=lowest")

    intoxication_level = fields.Integer(
        'Intoxication',
        help="the level of intoxication is associated with addiction and "
        "increases the personal and social damage a substance may do. \n"
        "Using Henningfield rating. 1=highest and 6=lowest")

    route_oral = fields.Boolean('Oral')

    route_popping = fields.Boolean(
        'Skin Popping',
        help="Subcutaneous or Intradermical administration")

    route_inhaling = fields.Boolean(
        'Smoke / Inhale',
        help="Insufflation, excluding nasal")

    route_sniffing = fields.Boolean(
        'Sniffing',
        help="Also called snorting - inhaling through the nares")

    route_injection = fields.Boolean(
        'Injection',
        help="Injection - Intravenous, Intramuscular...")

    dea_schedule_i = fields.Boolean(
        'DEA schedule I',
        help="Schedule I and II drugs have a high potential for abuse. "
        "They require greater storage security and have a quota on "
        "manufacturing, among other restrictions. Schedule I drugs are "
        "available for research only and have no approved medical use; "
        "Schedule II drugs are available only by prescription "
        "(unrefillable) and require a form for ordering. Schedule III "
        "and IV drugs are available by prescription, may have five "
        "refills in 6 months, and may be ordered orally. "
        "Some Schedule V drugs are available over the counter")

    dea_schedule_ii = fields.Boolean(
        'II',
        help="Schedule I and II drugs have a high potential for abuse."
        "They require greater storage security and have a quota on"
        "manufacturing, among other restrictions. Schedule I drugs are"
        "available for research only and have no approved medical use; "
        "Schedule II drugs are available only by prescription "
        "(unrefillable) and require a form for ordering. Schedule III "
        "and IV drugs are available by prescription, may have five"
        "refills in 6 months, and may be ordered orally. "
        "Some Schedule V drugs are available over the counter")

    dea_schedule_iii = fields.Boolean(
        'III',
        help="Schedule I and II drugs have a high potential for abuse. "
        "They require greater storage security and have a quota on "
        "manufacturing, among other restrictions. Schedule I drugs are "
        "available for research only and have no approved medical use; "
        "Schedule II drugs are available only by prescription "
        "(unrefillable) and require a form for ordering. Schedule III "
        "and IV drugs are available by prescription, may have five "
        "refills in 6 months, and may be ordered orally. "
        "Some Schedule V drugs are available over the counter")

    dea_schedule_iv = fields.Boolean(
        'IV',
        help="Schedule I and II drugs have a high potential for abuse. "
        "They require greater storage security and have a quota on "
        "manufacturing, among other restrictions. Schedule I drugs are "
        "available for research only and have no approved medical use; "
        "Schedule II drugs are available only by prescription "
        "(unrefillable) and require a form for ordering. Schedule III "
        "and IV drugs are available by prescription, may have five "
        "refills in 6 months, and may be ordered orally. "
        "Some Schedule V drugs are available over the counter")

    dea_schedule_v = fields.Boolean(
        'V',
        help="Schedule I and II drugs have a high potential for abuse. "
        "They require greater storage security and have a quota on "
        "manufacturing, among other restrictions. Schedule I drugs are "
        "available for research only and have no approved medical use; "
        "Schedule II drugs are available only by prescription "
        "(unrefillable) and require a form for ordering. Schedule III "
        "and IV drugs are available by prescription, may have five "
        "refills in 6 months, and may be ordered orally. "
        "Some Schedule V drugs are available over the counter")

    info = fields.Text('Extra Info', translate=True)

    @classmethod
    def __setup__(cls):
        super(DrugsRecreational, cls).__setup__()

        t = cls.__table__()
        cls._sql_constraints = [
            ('name_unique', Unique(t, t.name),
                'The Recreational Drug name must be unique'),
            ('code_unique', Unique(t, t.code),
                'The Recreational Drug CODE must be unique'),
        ]


class PatientRecreationalDrugs(ModelSQL, ModelView):
    'Patient use of Recreational Drugs'
    __name__ = 'gnuhealth.patient.recreational_drugs'

    patient = fields.Many2One('gnuhealth.patient', 'Patient')
    recreational_drug = fields.Many2One(
        'gnuhealth.drugs_recreational',
        'Recreational Drug')


# CAGE questionnaire to assess patient dependency to alcohol
class PatientCAGE(ModelSQL, ModelView):
    'Patient CAGE Questionnaire'
    __name__ = 'gnuhealth.patient.cage'

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

    evaluation_date = fields.DateTime('Date')

    cage_c = fields.Boolean(
        'Hard to Cut down', help='Have you ever felt you '
        'needed to Cut down on your drinking?')
    cage_a = fields.Boolean(
        'Angry with Critics', help='Have people Annoyed '
        'you by criticizing your drinking?')
    cage_g = fields.Boolean(
        'Guilt', help='Have you ever felt Guilty about '
        'drinking?')
    cage_e = fields.Boolean(
        'Eye-opener', help='Have you ever felt you '
        'needed a drink first thing in the morning (Eye-opener) to steady '
        'your nerves or to get rid of a hangover?')

    cage_score = fields.Integer('CAGE Score')

    # Show the icon depending on the CAGE Score
    cage_warning_icon = \
        fields.Function(
            fields.Char('Cage Warning Icon'),
            'get_cage_warning_icon')

    def get_cage_warning_icon(self, name):
        if (self.cage_score > 1):
            return 'gnuhealth-warning'

    @fields.depends('cage_c', 'cage_a', 'cage_g', 'cage_e')
    def on_change_with_cage_score(self):
        total = 0

        if self.cage_c:
            total = total + 1
        if self.cage_a:
            total = total + 1
        if self.cage_g:
            total = total + 1
        if self.cage_e:
            total = total + 1

        return total

    @staticmethod
    def default_evaluation_date():
        return datetime.now()

    @staticmethod
    def default_cage_score():
        return 0

    @classmethod
    def __setup__(cls):
        super(PatientCAGE, cls).__setup__()

        # Do not cache default_key as it depends on time
        cls.__rpc__['default_get'].cache = None


class MedicalPatient(metaclass=PoolMeta):
    __name__ = 'gnuhealth.patient'

    exercise = fields.Boolean('Exercise')
    exercise_minutes_day = fields.Integer(
        'Minutes / day',
        help="How many minutes a day the patient exercises")
    sleep_hours = fields.Integer(
        'Hours of sleep',
        help="Average hours of sleep per day")
    sleep_during_daytime = fields.Boolean(
        'Sleeps at daytime',
        help="Check if the patient sleep hours are during daylight rather "
        "than at night")
    number_of_meals = fields.Integer('Meals per day')
    vegetarian_type = fields.Many2One(
        'gnuhealth.vegetarian_types', 'Vegetarian')
    diet_belief = fields.Many2One(
        'gnuhealth.diet.belief',
        'Belief', help="Enter the patient belief or religion")

    eats_alone = fields.Boolean(
        'Eats alone',
        help="Check this box if the patient eats by him / herself.")
    salt = fields.Boolean(
        'Salt',
        help="Check if patient consumes salt with the food")
    coffee = fields.Boolean('Coffee')
    coffee_cups = fields.Integer(
        'Cups per day',
        help="Number of cup of coffee a day")
    soft_drinks = fields.Boolean(
        'Soft drinks (sugar)',
        help="Check if the patient consumes soft drinks with sugar")
    diet = fields.Boolean(
        'Currently on a diet',
        help="Check if the patient is currently on a diet")
    diet_info = fields.Char(
        'Diet info',
        help="Short description on the diet")
    smoking = fields.Boolean('Smokes')
    smoking_number = fields.Integer('Cigarretes a day')
    ex_smoker = fields.Boolean('Ex-smoker')
    second_hand_smoker = fields.Boolean(
        'Passive smoker',
        help="Check it the patient is a passive / second-hand smoker")
    age_start_smoking = fields.Integer('Age started to smoke')
    age_quit_smoking = fields.Integer(
        'Age of quitting',
        help="Age of quitting smoking")
    alcohol = fields.Boolean('Drinks Alcohol')
    age_start_drinking = fields.Integer(
        'Age started to drink',
        help="Date to start drinking")
    age_quit_drinking = fields.Integer(
        'Age quit drinking',
        help="Date to stop drinking")
    ex_alcoholic = fields.Boolean('Ex alcoholic')
    alcohol_beer_number = fields.Integer('Beer / day')
    alcohol_wine_number = fields.Integer('Wine / day')
    alcohol_liquor_number = fields.Integer('Liquor / day')
    drug_usage = fields.Boolean('Drug Habits')
    ex_drug_addict = fields.Boolean('Ex drug addict')
    drug_iv = fields.Boolean(
        'IV drug user',
        help="Check this option if the patient injects drugs")
    age_start_drugs = fields.Integer(
        'Age started drugs',
        help="Age of start drugs")
    age_quit_drugs = fields.Integer(
        'Age quit drugs',
        help="Date of quitting drugs")
    recreational_drugs = fields.One2Many(
        'gnuhealth.patient.recreational_drugs', 'patient', 'Drugs')
    traffic_laws = fields.Boolean(
        'Obeys Traffic Laws',
        help="Check if the patient is a safe driver")
    car_revision = fields.Boolean(
        'Car Revision',
        help="Maintain the vehicle. Do periodical checks - tires,breaks ...")
    car_seat_belt = fields.Boolean(
        'Seat belt',
        help="Safety measures when driving : safety belt")
    car_child_safety = fields.Boolean(
        'Car Child Safety',
        help="Safety measures when driving : child seats, "
        "proper seat belting, not seating on the front seat, ....")
    home_safety = fields.Boolean(
        'Home safety',
        help="Keep safety measures for kids in the kitchen, "
        "correct storage of chemicals, ...")
    motorcycle_rider = fields.Boolean(
        'Motorcycle Rider',
        help="The patient rides motorcycles")
    helmet = fields.Boolean(
        'Uses helmet',
        help="The patient uses the proper motorcycle helmet")

    lifestyle_info = fields.Text('Extra Information')

    sexual_preferences = fields.Selection([
        (None, ''),
        ('h', 'Heterosexual'),
        ('g', 'Homosexual'),
        ('b', 'Bisexual'),
        ('t', 'Transexual'),
    ], 'Sexual Preferences', sort=False)

    sexual_preferences_str = sexual_preferences.translated(
        'sexual_preferences')

    sexual_practices = fields.Selection([
        (None, ''),
        ('s', 'Safe / Protected sex'),
        ('r', 'Risky / Unprotected sex'),
    ], 'Sexual Practices', sort=False)

    sexual_practices_str = sexual_practices.translated('sexual_practices')

    sexual_partners = fields.Selection([
        (None, ''),
        ('m', 'Monogamous'),
        ('t', 'Polygamous'),
    ], 'Sexual Partners', sort=False)

    sexual_partners_str = sexual_partners.translated('sexual_partners')

    sexual_partners_number = fields.Integer('Number of sexual partners')

    first_sexual_encounter = fields.Integer('Age first sexual encounter')

    anticonceptive = fields.Selection([
        (None, ''),
        ('0', 'None'),
        ('1', 'Pill / Minipill'),
        ('2', 'Male condom'),
        ('3', 'Vasectomy'),
        ('4', 'Female sterilisation'),
        ('5', 'Intra-uterine device'),
        ('6', 'Withdrawal method'),
        ('7', 'Fertility cycle awareness'),
        ('8', 'Contraceptive injection'),
        ('9', 'Skin Patch'),
        ('10', 'Female condom'),
    ], 'Contraceptive Method', sort=False)

    sex_oral = fields.Selection([
        (None, ''),
        ('0', 'None'),
        ('1', 'Active'),
        ('2', 'Passive'),
        ('3', 'Both'),
    ], 'Oral Sex', sort=False)

    sex_anal = fields.Selection([
        (None, ''),
        ('0', 'None'),
        ('1', 'Active'),
        ('2', 'Passive'),
        ('3', 'Both'),
    ], 'Anal Sex', sort=False)

    prostitute = fields.Boolean(
        'Prostitute',
        help="Check if the patient (he or she) is a prostitute")
    sex_with_prostitutes = fields.Boolean(
        'Sex with prostitutes',
        help="Check if the patient (he or she) has sex with prostitutes")

    sexuality_info = fields.Text('Extra Information')

    cage = fields.One2Many(
        'gnuhealth.patient.cage',
        'patient', 'CAGE')
