package org.hisp.dhis.android.core.category;

import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;

import org.hisp.dhis.android.core.common.LinkModelHandler;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;

public class CategoryComboHandlerShould {

    @Mock
    private LinkModelHandler<CategoryOption, CategoryOptionComboCategoryOptionLinkModel>
            categoryOptionComboCategoryOptionLinkHandler;

    @Mock
    private LinkModelHandler<Category, CategoryCategoryComboLinkModel> mockComboLinkStore;

    @Mock
    private CategoryOptionComboHandler mockOptionComboHandler;

    @Mock
    private CategoryComboStore mockComboStore;

    private CategoryComboHandler categoryComboHandler;

    @Before
    public void setUp() throws Exception {


        MockitoAnnotations.initMocks(this);


        categoryComboHandler = new CategoryComboHandler(mockComboStore, categoryOptionComboCategoryOptionLinkHandler,
                mockComboLinkStore, mockOptionComboHandler);
    }

    @Test
    public void handle_a_new_category_combo() {
        CategoryCombo combo = givenACategoryCombo();

        when(mockComboStore.update(any(CategoryCombo.class), any(CategoryCombo.class))).thenReturn(
                false);

        categoryComboHandler.handle(combo);

        verify(mockComboStore).update(combo, combo);
        verify(mockComboStore).insert(combo);

    }

    @Test
    public void handle_a_deleted_category_combo() {
        CategoryCombo deletedCombo = givenADeletedCategoryCombo();

        categoryComboHandler.handle(deletedCombo);
        verify(mockComboStore).delete(deletedCombo);
    }

    @Test
    public void handle_updated_category() {
        CategoryCombo updatedCombo = givenACategoryCombo();

        when(mockComboStore.update(any(CategoryCombo.class), any(CategoryCombo.class))).thenReturn(
                true);

        categoryComboHandler.handle(updatedCombo);

        verify(mockComboStore).update(updatedCombo, updatedCombo);
        verifyZeroInteractions(mockComboStore);

    }

    private CategoryCombo givenADeletedCategoryCombo() {
        Date today = new Date();

        return CategoryCombo.builder()
                .uid("m2jTvAj5kkm")
                .deleted(true)
                .code("BIRTHS")
                .created(today)
                .name("Births")
                .displayName("Births")
                .categoryOptionCombos(givenAListOfCategoriesOptionCombo())
                .categories(givenAListOfCategories())
                .build();
    }

    private CategoryCombo givenACategoryCombo() {
        Date today = new Date();

        return CategoryCombo.builder()
                .uid("m2jTvAj5kkm")
                .code("BIRTHS")
                .created(today)
                .name("Births")
                .displayName("Births")
                .categoryOptionCombos(givenAListOfCategoriesOptionCombo())
                .categories(givenAListOfCategories())
                .build();
    }

    private List<Category> givenAListOfCategories() {
        List<Category> list = new ArrayList<>();

        list.add(givenACategory());

        return list;
    }

    private List<CategoryOptionCombo> givenAListOfCategoriesOptionCombo() {
        List<CategoryOptionCombo> list = new ArrayList<>();

        list.add(givenACategoryComboOption());

        return list;
    }

    private List<CategoryOption> givenAListOfCategoriesOptions() {
        List<CategoryOption> list = new ArrayList<>();

        list.add(givenACategoryOption());

        return list;
    }

    private CategoryOption givenACategoryOption() {
        Date today = new Date();

        return CategoryOption.builder()
                .uid("jRbMi0aBjYn")
                .code("MLE")
                .created(today)
                .name("Male")
                .shortName("Male")
                .displayName("Male")
                .build();
    }

    private CategoryOptionCombo givenACategoryComboOption() {
        Date today = new Date();

        //noinspection ConstantConditions
        return CategoryOptionCombo.builder()
                .uid("NZAKyj67WW2")
                .code("BIRTHS_ATTENDED")
                .created(today)
                .name("SECHN, Male")
                .shortName("SECHN, Male")
                .displayName("SECHN, Male")
                .categoryOptions(givenAListOfCategoriesOptions())
                .build();
    }

    private Category givenACategory() {
        Date today = new Date();

        return Category.builder()
                .uid("KfdsGBcoiCa")
                .code("BIRTHS_ATTENDED")
                .created(today)
                .name("Births attended by")
                .shortName("Births attended by")
                .displayName("Births attended by")
                .build();
    }
}
@@ -50,181 +50,59 @@
 ort 
-static org.mockito.Matchers.any;%0Aimport static org.mockito.Mockito.verify;%0Aimport static org.mockito.Mockito.verifyZeroInteractions;%0Aimport static org.mockito.Mockito.when;%0A
+org.hisp.dhis.android.core.common.LinkModelHandler;
 %0Aimp
@@ -135,38 +135,35 @@
 core.common.
-LinkModelHandl
+OrphanClean
 er;%0Aimport o
@@ -342,16 +342,284 @@
 .List;%0A%0A
+import static org.mockito.Matchers.any;%0Aimport static org.mockito.Matchers.anyListOf;%0Aimport static org.mockito.Mockito.never;%0Aimport static org.mockito.Mockito.verify;%0Aimport static org.mockito.Mockito.verifyZeroInteractions;%0Aimport static org.mockito.Mockito.when;%0A%0A
 public c
@@ -1041,24 +1041,120 @@
 omboStore;%0A%0A
+    @Mock%0A    private OrphanCleaner%3CCategoryCombo, CategoryOptionCombo%3E categoryOptionCleaner;%0A%0A
     private 
@@ -1252,18 +1252,16 @@
 ption %7B%0A
-%0A%0A
         
@@ -1297,17 +1297,16 @@
 this);%0A%0A
-%0A
         
@@ -1473,16 +1473,39 @@
 oHandler
+, categoryOptionCleaner
 );%0A    %7D
@@ -1883,24 +1883,165 @@
 ert(combo);%0A
+        verify(categoryOptionCleaner, never()).deleteOrphan(%0A                any(CategoryCombo.class), anyListOf(CategoryOptionCombo.class));
 %0A    %7D%0A%0A    
@@ -2266,24 +2266,166 @@
 etedCombo);%0A
+        verify(categoryOptionCleaner, never()).deleteOrphan(%0A                any(CategoryCombo.class), anyListOf(CategoryOptionCombo.class));%0A
     %7D%0A%0A    @
@@ -2821,24 +2821,156 @@
 omboStore);%0A
+        verify(categoryOptionCleaner).deleteOrphan(%0A                any(CategoryCombo.class), anyListOf(CategoryOptionCombo.class));
 %0A    %7D%0A%0A    

add tests