package com.uva.rafael.tfg_goniometer.presenter;

import android.app.Fragment;
import android.text.TextUtils;

import com.uva.rafael.tfg_goniometer.R;
import com.uva.rafael.tfg_goniometer.interfaces.PresenterFunctions;
import com.uva.rafael.tfg_goniometer.model.MainModel;
import com.uva.rafael.tfg_goniometer.view.fragments.NuevoPacienteFragment;

import java.util.ArrayList;

/**
 * Este es el Presentador asociado al <tt>Fragment NuevoPacienteFragment</tt> de la aplicación. Se
 * encarga de llevar a cabo toda la lógica asociada a las acciones del usuario realizadas en la IU.
 *
 * <p>En concreto, se encarga de filtrar toda la información introducida por el usuario con respecto
 * al nuevo paciente y se la envía al Modelo, con el fin de introducirla finalmente en la Base de
 * Datos. También se encarga de indicar a la Vista que muestre al usuario si se ha producido algún
 * error durante el filtrado o almacenamiento de esta información.</p>
 *
 * <p>Esta clase forma parte de la aplicación TFG-Goniometer, desarrollada para el Trabajo de
 * Fin de Grado - Grado en Ingeniería Informatica (Universidad de Valladolid)</p>
 *
 * @author Rafael Matamoros Luque
 * @see NuevoPacienteFragment
 * @see MainModel
 * @version 1.0
 */

public class NuevoPacientePresenter implements PresenterFunctions,
        PresenterFunctions.NuevoPacienteFunctions {

    private final MainModel model;
    // Referencias al fragmento (Vista) con el que esta asociado y al Modelo de la aplicación
    private NuevoPacienteFragment fragment;

    /**
     * Constructor principal de la clase
     *
     * @param fragment Fragmento (Vista) con la que mantiene una relación 1-a-1.
     * @param model    Modelo (único) de la aplicación.
     */
    public NuevoPacientePresenter(Fragment fragment, MainModel model) {
        this.fragment = (NuevoPacienteFragment) fragment;
        this.model = model;
    }

    /**
     * Evento <tt>ClickListener</tt> que se llama cuando el usuario ha pulsado sobre el botón
     * "GUARDAR" en <tt>NuevoPacienteFragment</tt>.
     * <p>
     * <p>Se encarga de:
     * <p>
     * 1.- Verificar que el usuario ha introducido toda la información obligatoria (marcada con *).
     * 2.- Filtrar la información a un formato que se pueda utilizar para introducirla en la
     * Base de Datos.
     * 3.- Enviar la información, una vez filtrada, al Modelo para que sea introducida en la Base de
     * Datos.
     * 4.- Solicitar a la Vista (<tt>NuevoPacienteFragment</tt>) que muestre un mensaje dependiendo
     * de si la inserción en la Base de Datos ha sido exitosa o no.
     * 5.- Si la inserción se realizó con éxito, borrar el <tt>Fragment</tt> actual y mostrar el
     * listado de pacientes actualizado con el nuevo paciente ya almacenado.</p>
     *
     * @param nombre_editText                  Nombre del paciente (Obligatorio)
     * @param edad_editText                    Edad del paciente (Obligatorio)
     * @param sexo_radioGroup                  Sexo del paciente (Obligatorio)
     * @param id_editText                      ID del paciente (Opcional)
     * @param telefono_editText                Teléfono del paciente (Opcional)
     * @param direccion_editText               Dirección del paciente (Opcional)
     * @param sintomas_editText                Síntomas del paciente (Opcional)
     * @param diagnostico_editText             Diagnóstico del paciente (Obligatorio)
     * @param tratamiento_previo_editText      Tratamiento previo que ha estado siguiendo el paciente
     *                                         (Opcional)
     * @param tratamiento_actual_editText      Tratamiento que esta siguiendo actualmente el paciente
     *                                         (Opcional)
     * @param comentarios_adicionales_editText Comentarios adicionales que se necesiten introducir
     *                                         (Opcional)
     * @param tags_editText                    Etiquetas para recuperar facilmente la información
     *                                         del paciente al buscarlo en el listado de pacientes
     *                                         (Obligatorio)
     */
    @SuppressWarnings("ConstantConditions")
    @Override
    public void onSaveClicked(String nombre_editText, String edad_editText, int sexo_radioGroup,
                              String id_editText, String telefono_editText, String direccion_editText,
                              String sintomas_editText, String diagnostico_editText,
                              String tratamiento_previo_editText, String tratamiento_actual_editText,
                              String comentarios_adicionales_editText, String tags_editText) {

        /*
         * Variables locales donde almacenar la información introducida por el usuario después de
         * filtrarla y posteriormente insertarla en la BD
         */
        String nombre, sexo, direccion, sintomas, diagnostico, tratamiento_previo, tratamiento_actual,
                comentarios;
        int edad, id;
        long telefono;
        ArrayList<String> tags = new ArrayList<>();

        /*
         * Si no se ha introducido ningún nombre, asignar null a la variable local para devolver un
         * error al usuario
         */
        nombre = (!nombre_editText.trim().equals("")) ? nombre_editText : null;

        // En función del ID del RadioButton, asignar un valor u otro a la variable local
        if (sexo_radioGroup == R.id.hombre)
            sexo = fragment.getText(R.string.hombre).toString().toUpperCase();
        else
            sexo = fragment.getText(R.string.mujer).toString().toUpperCase();

        /*
         * Si no se ha introducido ningún valor en alguno de estos campos, asignar null para
         * devolver un error al usuario, o la cadena de texto "NULL" si el campo no es obligatorio
         */
        direccion = (!direccion_editText.trim().equals("")) ? direccion_editText : "NULL";
        sintomas = (!sintomas_editText.trim().equals("")) ? sintomas_editText : "NULL";
        diagnostico = (!diagnostico_editText.trim().equals("")) ? diagnostico_editText : null;
        tratamiento_previo = (!tratamiento_previo_editText.trim().equals("")) ?
                tratamiento_previo_editText : "NULL";
        tratamiento_actual = (!tratamiento_actual_editText.trim().equals("")) ?
                tratamiento_actual_editText : "NULL";
        comentarios = (!comentarios_adicionales_editText.trim().equals("")) ?
                comentarios_adicionales_editText : "NULL";

        /*
         * Si no se ha introducido ningún valor en alguno de estos campos, asignar el valor -1 para
         * devolver un error al usuario (en caso de ser un campo obligatorio) o -2 (en caso de ser
         * un campo opcional)
         */
        edad = (!edad_editText.trim().equals("")) ? Integer.parseInt(edad_editText) : -1;
        id = (!id_editText.trim().equals("")) ? Integer.parseInt(id_editText) : -1;
        telefono = (!telefono_editText.trim().equals("")) ? Long.parseLong(telefono_editText) : -2;

        if (!tags_editText.trim().equals("")) {
            // El usuario ha introducido algo en el campo "tags"
            try {
                // Se hace una separación de las distintas etiquetas separados por ,
                String etiquetas[] = tags_editText.replace(" ", ",").split(",");
                // Se añaden al ArrayList (variable local)
                for (String etiqueta : etiquetas) {
                    if (!etiqueta.isEmpty())
                        // Primera letra con mayúsculas, el resto en minúsculas
                        tags.add(etiqueta.substring(0, 1).toUpperCase()
                                + etiqueta.substring(1).toLowerCase());
                }
            } catch (IllegalArgumentException e) {
                // En caso de que sólo haya introducido una etiqueta
                tags.add(tags_editText);
            }
        }

        // Comprobación de que todos los campos que son obligatorios han sido rellenados
        if (nombre == null || edad == -1 || diagnostico == null || tags.isEmpty() || id == -1) {
            // De no ser así, indicar a la Vista que muestre un error al usuario
            fragment.displayErrorUser();
            return;
        }

        // Se crea un nuevo ArrayList con la información del paciente
        ArrayList<String> patient = new ArrayList<>();
        patient.add(0, nombre.trim()); // Nombre
        patient.add(1, String.valueOf(edad)); // Edad
        patient.add(2, sexo); // Sexo
        patient.add(3, String.valueOf(id).trim()); // ID
        patient.add(4, diagnostico); // Diagnóstico
        patient.add(5, TextUtils.join(", ", tags)); // Tags
        patient.add(6, String.valueOf(telefono)); // Teléfono
        patient.add(7, direccion); // Dirección
        patient.add(8, sintomas); // Síntomas
        patient.add(9, tratamiento_previo); // Tratamiento previo
        patient.add(10, tratamiento_actual); // Tratamiento actual
        patient.add(11, comentarios); // Comentarios adicionales

        // Se envía la información al Modelo para insertar el paciente en la BD
        long resultado = model.storePatient(patient);

        if (resultado > 0) {
            /*
             * El paciente se ha podido almacenar con éxito. Notificar a la vista que muestre un
             * mensaje indicando esta situación al usuario
             */
            fragment.displaySuccess();

            /*
             * Recuperar el Fragment que se encontraba en primera posición en el BackStack con el
             * listado de pacientes actualizado (incluyendo este nuevo paciente)
             */
            fragment.getFragmentManager().popBackStack();

            // Borrar el Fragment actual
            fragment.getFragmentManager()
                    .beginTransaction()
                    .remove(fragment)
                    .commit();
        } else if (resultado == -1)
               /*
                * Se ha producido un error al introducir el paciente en la BD. Notificar a la Vista
                * para que informe de esta situación al usuario
                */
            fragment.displayErrorDatabase();
        else
                /*
                 * Se ha intentado introducir un paciente que ya existe en la BD. Notificar a la
                 * Vista para que informe de esta situación al usuario
                 */
            fragment.displayErrorExistingPatient();
    }

    /**
     * Perform any final cleanup before an activity is destroyed.
     *
     * Se encarga de liberar la referencia al <tt>Fragment</tt> con el que esta asociado.
     */
    @Override
    public void onDestroy() {
        fragment = null;
    }
}
