package com.expidev.gcmapp.support.v4.content;

import static com.expidev.gcmapp.Constants.ARG_GUID;
import static com.expidev.gcmapp.Constants.PREFS_SETTINGS;
import static com.expidev.gcmapp.Constants.PREF_CURRENT_MINISTRY;
import static org.ccci.gto.android.common.db.AbstractDao.bindValues;

import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;

import com.expidev.gcmapp.db.Contract;
import com.expidev.gcmapp.db.GmaDao;
import com.expidev.gcmapp.model.Assignment;
import com.expidev.gcmapp.model.Ministry;
import com.expidev.gcmapp.utils.BroadcastUtils;

import org.ccci.gto.android.common.support.v4.content.AsyncTaskBroadcastReceiverSharedPreferencesChangeLoader;

import java.util.EnumSet;
import java.util.List;

public class CurrentAssignmentLoader extends AsyncTaskBroadcastReceiverSharedPreferencesChangeLoader<Assignment> {
    public static final String ARG_LOAD_MINISTRY = CurrentAssignmentLoader.class.getSimpleName() + ".ARG_LOAD_MINISTRY";

    private final GmaDao mDao;

    @Nullable
    private final String mGuid;
    private final boolean mLoadMinistry;

    public CurrentAssignmentLoader(@NonNull final Context context, @Nullable final Bundle args) {
        super(context, context.getSharedPreferences(PREFS_SETTINGS, Context.MODE_PRIVATE));
        mDao = GmaDao.getInstance(context);
        mGuid = args != null ? args.getString(ARG_GUID) : null;
        mLoadMinistry = args != null && args.getBoolean(ARG_LOAD_MINISTRY, false);

        // setup listeners for events
        if(mGuid != null) {
            addPreferenceKey(PREF_CURRENT_MINISTRY);
            addIntentFilter(BroadcastUtils.updateAssignmentsFilter(mGuid));
        }
    }

    @Override
    public Assignment loadInBackground() {
        // short-circuit if we don't have a valid guid
        if (mGuid == null) {
            return null;
        }

        // load the current active assignment
        final String ministryId = mPrefs.getString(PREF_CURRENT_MINISTRY, Ministry.INVALID_ID);
        Assignment assignment = mDao.find(Assignment.class, mGuid, ministryId);

        // reset to default assignment if a current current assignment isn't found
        if (assignment == null) {
            assignment = initActiveAssignment();
        }

        // load the associated ministry if required
        if (assignment != null && mLoadMinistry) {
            loadMinistry(assignment);
        }

        //TODO: validate MCC when possible

        // return the assignment
        return assignment;
    }

    private Assignment initActiveAssignment() {
        final List<Assignment> assignments =
                mDao.get(Assignment.class, Contract.Assignment.SQL_WHERE_GUID, bindValues(mGuid));

        // short-circuit if there are no assignments for the current user
        if (assignments.size() == 0) {
            return null;
        }

        // find the default assignment based on role
        Assignment assignment = null;
        for (final Assignment current : assignments) {
            // XXX: this currently relies on Roles being ordered from most important to least important
            if (assignment == null || current.getRole().ordinal() < assignment.getRole().ordinal()) {
                assignment = current;
            }
        }
        assert assignment != null : "there is at least 1 assignment in assignments, so this should never be null";

        // set an MCC if one is not already selected
        if (assignment.getMcc() == Ministry.Mcc.UNKNOWN) {
            updateMcc(assignment);
        }

        mPrefs.edit().putString(PREF_CURRENT_MINISTRY, assignment.getMinistryId()).apply();

        // return the found assignment
        return assignment;
    }

    private void updateMcc(@NonNull final Assignment assignment) {
        loadMinistry(assignment);

        // set the MCC based off of what is available for the ministry
        final Ministry ministry = assignment.getMinistry();
        if (ministry != null) {
            // pick a random MCC
            final EnumSet<Ministry.Mcc> mccs = ministry.getMccs();
            assignment.setMcc(mccs.size() > 0 ? mccs.iterator().next() : Ministry.Mcc.UNKNOWN);

            // update the assignment
            mDao.update(assignment, new String[] {Contract.Assignment.COLUMN_MCC});

            //TODO: should we broadcast this update?
        }
    }

    private void loadMinistry(@NonNull final Assignment assignment) {
        if (assignment.getMinistry() == null) {
            assignment.setMinistry(mDao.find(Ministry.class, assignment.getMinistryId()));
        }
    }
}

@@ -2498,21 +2498,16 @@
       //
-TODO:
  validat
@@ -2525,16 +2525,216 @@
 possible
+%0A        if (assignment != null && assignment.getMinistry() != null &&%0A                !assignment.getMinistry().getMccs().contains(assignment.getMcc())) %7B%0A            updateMcc(assignment);%0A        %7D
 %0A%0A      
@@ -4049,32 +4049,62 @@
 t assignment) %7B%0A
+        assert mGuid != null;%0A
         loadMini
@@ -4311,14 +4311,16 @@
 k a 
+%22
 random
+%22
  MCC
@@ -4403,26 +4403,33 @@
     
-assignment.setMcc(
+final Ministry.Mcc mcc = 
 mccs
@@ -4487,17 +4487,16 @@
 .UNKNOWN
-)
 ;%0A%0A     
@@ -4530,146 +4530,358 @@
 ment
-%0A            mDao.update(assignment, new String%5B%5D %7BContract.Assignment.COLUMN_MCC%7D);%0A%0A            //TODO: should we broadcast this update?
+ if the mcc is changing%0A            if (mcc != assignment.getMcc()) %7B%0A                assignment.setMcc(mcc);%0A                mDao.update(assignment, new String%5B%5D %7BContract.Assignment.COLUMN_MCC%7D);%0A%0A                // broadcast the MCC update%0A                getContext().sendBroadcast(BroadcastUtils.updateAssignmentsBroadcast(mGuid));%0A            %7D
 %0A   

validate the selected MCC for a ministry