package com.mobify.astro.plugins.layouts;

import android.content.Context;
import android.view.View;
import android.view.ViewGroup;

import com.mobify.astro.ActivityTestBase;
import com.mobify.astro.AstroActivity;

import org.json.JSONObject;
import org.junit.Before;
import org.junit.Test;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;

public class AnimatableSectionedContainerViewTest extends ActivityTestBase {

    class ExtendedTestView extends AnimatableSectionedContainerView {
        public ExtendedTestView(Context context) {
            super(context);
        }

        public boolean hasTopViews() {
            return super.hasTopViews();
        }

        public boolean hasMiddleView() {
            return hasMiddleView;
        }

        public boolean hasBottomViews() {
            return super.hasBottomViews();
        }

        public int numberTopViews() {
            return super.numberTopViews();
        }

        public int numberBottomViews() {
            return super.numberBottomViews();
        }

        public int indexAtBottomOfTopViews() {
            return super.indexAtBottomOfTopViews();
        }

        public int middleIndex() {
            return middleViewIndex;
        }

        public int indexAtTopOfBottomViews() {
            return startIndexBottomView();
        }
    }

    ExtendedTestView testView;
    View topView1;
    View middleView1;
    View bottomView1;
    View topView2;
    View bottomView2;

    private void checkVisibility(int startIndex, int numberItems, int visibility) {
        for (int i = startIndex; i < numberItems; i++) {
            assertEquals(visibility, testView.getChildAt(i).getVisibility());
        }
    }

    private void setupContainerWithViews() throws Exception {
        AstroActivity testActivity = getActivity();
        topView1 = new View(testActivity);
        middleView1 = new View(testActivity);
        bottomView1 = new View(testActivity);
        topView2 = new View(testActivity);
        bottomView2 = new View(testActivity);

        testView.addTopView(topView1, null);
        testView.addMiddleView(middleView1);
        testView.addBottomView(bottomView1, null);
        testView.addTopView(topView2, null);
        testView.addBottomView(bottomView2, null);
    }

    @Before
    public void setup() {
        testView = new ExtendedTestView(getActivity());
        topView1 = null;
        middleView1 = null;
        bottomView1 = null;
        topView2 = null;
        bottomView2 = null;
    }

    @Test
    public void testInitialization() {
        assertFalse(testView.hasTopViews());
        assertTrue(testView.hasMiddleView());
        assertFalse(testView.hasBottomViews());
    }

    @Test
    public void testAddTopView() throws Exception {
        View firstTopView = new View(getActivity());
        testView.addTopView(firstTopView, null);
        assertTrue(testView.hasTopViews());
        assertEquals(1, testView.numberTopViews());
        assertEquals(0, testView.indexAtBottomOfTopViews());
        assertEquals(2, testView.getChildCount());
    }

    @Test
    public void testAddMiddleView() throws Exception {
        View middleView = new View(getActivity());
        testView.addMiddleView(middleView);
        assertTrue(testView.hasMiddleView());
        assertEquals(0, testView.middleIndex());
        assertEquals(1, testView.getChildCount());
    }

    @Test
    public void testAddBottomView() throws Exception {
        View bottomView = new View(getActivity());
        testView.addBottomView(bottomView, null);
        assertTrue(testView.hasBottomViews());
        assertEquals(1, testView.indexAtTopOfBottomViews());
        assertEquals(2, testView.getChildCount());
    }

    @Test
    public void testAddViewWithVisibleOption() throws Exception {
        View view1 = new View(getActivity());
        JSONObject options = new JSONObject();
        options.put("visible", true);
        testView.addTopView(view1, options);

        assertEquals(View.VISIBLE, view1.getVisibility());
    }

    @Test
    public void testAddViewWithNonVisibleOption() throws Exception {
        View view1 = new View(getActivity());
        JSONObject options = new JSONObject();
        options.put("visible", false);
        testView.addTopView(view1, options);

        assertEquals(View.GONE, view1.getVisibility());
    }

    @Test
    public void testAddViewWithHeightOption() throws Exception {
        View view1 = new View(getActivity());
        JSONObject options = new JSONObject();
        options.put("height", 200);
        testView.addTopView(view1, options);

        int expectedHeight = (int) (200 * getActivity().getResources().getDisplayMetrics().density);
        assertEquals(expectedHeight, view1.getLayoutParams().height);
    }

    @Test
    public void testAddViewWithEmptyOptions() throws Exception {
        View view1 = new View(getActivity());
        JSONObject options = new JSONObject();
        testView.addTopView(view1, options);

        assertEquals(View.VISIBLE, view1.getVisibility());
        assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, view1.getLayoutParams().height);
    }

    @Test
    public void testAddViewWithNoOption() throws Exception {
        View view1 = new View(getActivity());
        testView.addTopView(view1, null);

        assertEquals(View.VISIBLE, view1.getVisibility());
        assertEquals(ViewGroup.LayoutParams.WRAP_CONTENT, view1.getLayoutParams().height);
    }

    @Test
    public void testAddTopViewWithMiddleAndBotomViews() throws Exception {
        View topView = new View(getActivity());
        View middleView = new View(getActivity());
        View bottomView = new View(getActivity());

        testView.addMiddleView(middleView);
        testView.addBottomView(bottomView, null);

        assertFalse(testView.hasTopViews());
        assertEquals(2, testView.getChildCount());

        testView.addTopView(topView, null);

        assertTrue(testView.hasTopViews());
        assertEquals(3, testView.getChildCount());
        assertEquals(1, testView.numberTopViews());
        assertEquals(0, testView.indexAtBottomOfTopViews());

        assertEquals(1, testView.middleIndex());
        assertEquals(2, testView.indexAtTopOfBottomViews());
    }

    @Test
    public void testAddTwoEachTypeView() throws Exception {
        setupContainerWithViews();

        assertTrue(testView.hasTopViews());
        assertTrue(testView.hasMiddleView());
        assertTrue(testView.hasBottomViews());

        assertEquals(5, testView.getChildCount());
        assertEquals(2, testView.numberTopViews());
        assertEquals(2, testView.numberBottomViews());

        assertEquals(1, testView.indexAtBottomOfTopViews());
        assertEquals(2, testView.middleIndex());
        assertEquals(3, testView.indexAtTopOfBottomViews());

        assertEquals(topView1, testView.getChildAt(0));
        assertEquals(topView2, testView.getChildAt(1));
        assertEquals(middleView1, testView.getChildAt(2));
        assertEquals(bottomView2, testView.getChildAt(3));
        assertEquals(bottomView1, testView.getChildAt(4));
    }

    @Test
    public void testRemoveTopViews() throws Exception {
        setupContainerWithViews();

        testView.removeTopViews();

        assertFalse(testView.hasTopViews());
        assertTrue(testView.hasMiddleView());
        assertTrue(testView.hasBottomViews());

        assertEquals(3, testView.getChildCount());
        assertEquals(0, testView.numberTopViews());
        assertEquals(2, testView.numberBottomViews());

        assertEquals(0, testView.middleIndex());
        assertEquals(1, testView.indexAtTopOfBottomViews());

        assertEquals(middleView1, testView.getChildAt(0));
        assertEquals(bottomView2, testView.getChildAt(1));
        assertEquals(bottomView1, testView.getChildAt(2));
    }

    @Test
    public void testRemoveMiddleView() throws Exception {
        setupContainerWithViews();

        testView.removeMiddleView();

        assertTrue(testView.hasTopViews());
        assertFalse(testView.hasMiddleView());
        assertTrue(testView.hasBottomViews());

        assertEquals(4, testView.getChildCount());
        assertEquals(2, testView.numberTopViews());
        assertEquals(2, testView.numberBottomViews());

        assertEquals(1, testView.indexAtBottomOfTopViews());
        assertEquals(2, testView.indexAtTopOfBottomViews());

        assertEquals(topView1, testView.getChildAt(0));
        assertEquals(topView2, testView.getChildAt(1));
        assertEquals(bottomView2, testView.getChildAt(2));
        assertEquals(bottomView1, testView.getChildAt(3));
    }

    @Test
    public void testRemoveBottomViews() throws Exception {
        setupContainerWithViews();

        testView.removeBottomViews();

        assertTrue(testView.hasTopViews());
        assertTrue(testView.hasMiddleView());
        assertFalse(testView.hasBottomViews());

        assertEquals(3, testView.getChildCount());
        assertEquals(2, testView.numberTopViews());
        assertEquals(0, testView.numberBottomViews());

        assertEquals(1, testView.indexAtBottomOfTopViews());
        assertEquals(2, testView.middleIndex());

        assertEquals(topView1, testView.getChildAt(0));
        assertEquals(topView2, testView.getChildAt(1));
        assertEquals(middleView1, testView.getChildAt(2));
    }

    @Test
    public void testSetVisibilityTopViews() throws Exception {
        setupContainerWithViews();

        checkVisibility(0, 5, View.VISIBLE);

        testView.setVisibilityTopViews(View.GONE);

        checkVisibility(0, 2, View.GONE);
        checkVisibility(2, 3, View.VISIBLE);

        testView.setVisibilityTopViews(View.VISIBLE);

        checkVisibility(0, 5, View.VISIBLE);
    }

    @Test
    public void testSetVisibilityBottomViews() throws Exception {
        setupContainerWithViews();

        checkVisibility(0, 5, View.VISIBLE);

        testView.setVisibilityBottomViews(View.GONE);

        checkVisibility(0, 3, View.VISIBLE);
        checkVisibility(3, 2, View.GONE);

        testView.setVisibilityBottomViews(View.VISIBLE);

        checkVisibility(0, 5, View.VISIBLE);
    }

    @Test
    public void testSetChildVisibilityChildNotPresent() throws Exception{
        setupContainerWithViews();

        View standaloneView = new View(getActivity());

        testView.setChildVisibility(standaloneView, View.GONE);

        checkVisibility(0, 5, View.VISIBLE);
    }

    @Test
    public void testSetChildVisibilityChild() throws Exception{
        setupContainerWithViews();

        View standaloneView = new View(getActivity());

        testView.setChildVisibility(standaloneView, View.GONE);

        checkVisibility(0, 5, View.VISIBLE);
    }

    @Test
    public void testHidingTopViewsWithHiddenViews() throws Exception{
        setupContainerWithViews();

        checkVisibility(0, 5, View.VISIBLE);

        testView.setChildVisibility(topView1, View.GONE);

        checkVisibility(0, 1, View.GONE);
        checkVisibility(1, 5, View.VISIBLE);

        testView.setVisibilityTopViews(View.GONE);

        checkVisibility(0, 2, View.GONE);
        checkVisibility(2, 3, View.VISIBLE);

        testView.setVisibilityTopViews(View.VISIBLE);

        checkVisibility(0, 1, View.GONE);
        checkVisibility(1, 5, View.VISIBLE);
    }

    @Test
    public void testHidingBottomViewsWithHiddenViews() throws Exception{
        setupContainerWithViews();

        checkVisibility(0, 5, View.VISIBLE);

        testView.setChildVisibility(bottomView1, View.GONE);

        checkVisibility(0, 4, View.VISIBLE);
        checkVisibility(4, 1, View.GONE);

        testView.setVisibilityBottomViews(View.GONE);

        checkVisibility(0, 3, View.VISIBLE);
        checkVisibility(3, 2, View.GONE);

        testView.setVisibilityBottomViews(View.VISIBLE);

        checkVisibility(0, 4, View.VISIBLE);
        checkVisibility(4, 1, View.GONE);
    }

}
