import * as TKUnit from "../../TKUnit";
import * as helper from "../helper";
import { View } from "tns-core-modules/ui/core/view";
import { Button } from "tns-core-modules/ui/button";
import { Page } from "tns-core-modules/ui/page";
import { ScrollView } from "tns-core-modules/ui/scroll-view";
import { LayoutBase } from "tns-core-modules/ui/layouts/layout-base";
import { StackLayout } from "tns-core-modules/ui/layouts/stack-layout";
import { GridLayout } from "tns-core-modules/ui/layouts/grid-layout";
import { ProxyViewContainer } from "tns-core-modules/ui/proxy-view-container";
import { ListView } from "tns-core-modules/ui/list-view";

export function test_add_children_to_attached_proxy() {
    const outer = new StackLayout();
    const proxy = new ProxyViewContainer();

    function testAction(views: Array<View>) {
        outer.addChild(createBtn("1"));
        outer.addChild(proxy);
        proxy.addChild(createBtn("2"));
        proxy.addChild(createBtn("3"));
        proxy.addChild(createBtn("4"));

        outer.addChild(createBtn("5"));

        assertNativeChildren(outer, ["1", "2", "3", "4", "5"]);
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_children_immediately_registered_in_parent_grid_layout() {
    const outer = new GridLayout();
    const proxy = new ProxyViewContainer();

    function testAction(views: Array<View>) {
        outer.addChild(proxy);
        proxy.addChild(createBtn("1"));

        assertNativeChildren(outer, ["1"]);
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_children_registered_in_parent_grid_layout_on_attach() {
    const outer = new GridLayout();
    const proxy = new ProxyViewContainer();

    function testAction(views: Array<View>) {

        proxy.addChild(createBtn("1"));
        outer.addChild(proxy);

        assertNativeChildren(outer, ["1"]);
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_add_children_to_detached_proxy() {
    const outer = new StackLayout();
    const proxy = new ProxyViewContainer();

    function testAction(views: Array<View>) {
        outer.addChild(createBtn("1"));

        proxy.addChild(createBtn("2"));
        proxy.addChild(createBtn("3"));
        proxy.addChild(createBtn("4"));
        outer.addChild(proxy);

        outer.addChild(createBtn("5"));

        assertNativeChildren(outer, ["1", "2", "3", "4", "5"]);
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_remove_proxy() {
    const outer = new StackLayout();
    const proxy = new ProxyViewContainer();

    outer.addChild(createBtn("1"));

    outer.addChild(proxy);
    proxy.addChild(createBtn("2"));
    proxy.addChild(createBtn("3"));
    proxy.addChild(createBtn("4"));

    outer.addChild(createBtn("5"));

    function testAction(views: Array<View>) {
        assertNativeChildren(outer, ["1", "2", "3", "4", "5"]);
        outer.removeChild(proxy);
        assertNativeChildren(outer, ["1", "5"]);
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_remove_child_of_attached_proxy() {
    const outer = new StackLayout();
    const proxy = new ProxyViewContainer();

    outer.addChild(createBtn("1"));

    outer.addChild(proxy);
    proxy.addChild(createBtn("2"));
    const testBtn = createBtn("3");
    proxy.addChild(testBtn);
    proxy.addChild(createBtn("4"));

    outer.addChild(createBtn("5"));

    function testAction(views: Array<View>) {
        assertNativeChildren(outer, ["1", "2", "3", "4", "5"]);
        proxy.removeChild(testBtn);
        assertNativeChildren(outer, ["1", "2", "4", "5"]);
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_insert_inside_proxy() {
    const outer = new StackLayout();
    const proxy = new ProxyViewContainer();

    outer.addChild(createBtn("1"));

    outer.addChild(proxy);
    proxy.addChild(createBtn("2"));
    proxy.addChild(createBtn("4"));

    outer.addChild(createBtn("5"));

    function testAction(views: Array<View>) {
        assertNativeChildren(outer, ["1", "2", "4", "5"]);
        proxy.insertChild(createBtn("3"), 1);
        assertNativeChildren(outer, ["1", "2", "3", "4", "5"]);
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_insert_after_proxy() {
    const outer = new StackLayout();
    const proxy = new ProxyViewContainer();

    outer.addChild(createBtn("1"));

    outer.addChild(proxy);
    proxy.addChild(createBtn("2"));
    proxy.addChild(createBtn("3"));
    proxy.addChild(createBtn("4"));

    function testAction(views: Array<View>) {
        assertNativeChildren(outer, ["1", "2", "3", "4"]);
        outer.insertChild(createBtn("5"), 2);
        assertNativeChildren(outer, ["1", "2", "3", "4", "5"]);
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_proxy_does_not_stop_request_layout_bubble() {
    const outer = new StackLayout();
    const proxy = new ProxyViewContainer();

    outer.addChild(createBtn("1"));
    outer.addChild(proxy);
    const btn = createBtn("2");
    proxy.addChild(btn);

    function testAction(views: Array<View>) {
        assertNativeChildren(outer, ["1", "2"]);
        waitUntilElementLayoutIsValid(outer);
        TKUnit.assert(outer.isLayoutValid, "outer container isLayoutValid should be true");
        btn.requestLayout();
        TKUnit.assertFalse(outer.isLayoutValid, "outer container isLayoutValid should be invalidated here");
    };

    helper.buildUIAndRunTest(outer, testAction);
}

export function test_proxy_iniside_page() {
    const proxy = new ProxyViewContainer();
    proxy.addChild(createBtn("1"));

    function testAction(views: Array<View>) {
        const page = <Page>views[1];
        waitUntilElementLayoutIsValid(page);
    };

    helper.buildUIAndRunTest(proxy, testAction);
}

export function test_proxy_inside_scroll_view() {
    const scroll = new ScrollView();
    const proxy = new ProxyViewContainer();
    scroll.content = proxy;

    proxy.addChild(createBtn("1"));

    function testAction(views: Array<View>) {
        const page = <Page>views[1];
        waitUntilElementLayoutIsValid(page);
    };

    helper.buildUIAndRunTest(scroll, testAction);
}

export function test_proxy_inside_border() {
    const scroll = new ScrollView();
    const proxy = new ProxyViewContainer();
    scroll.content = proxy;

    proxy.addChild(createBtn("1"));

    function testAction(views: Array<View>) {
        const page = <Page>views[1];
        waitUntilElementLayoutIsValid(page);
    };

    helper.buildUIAndRunTest(scroll, testAction);
}

export function test_proxy_inside_listview_itemTemplate_crash() {
    // Usually reproducible with an Angular component in the template
    // We use a simple declaration here to simulate it.
    const list = new ListView();
    list.items = ["item 1"];
    list.itemTemplate = `
    <ProxyViewContainer>
        <Label text="{{$value}}"></Label>
    </ProxyViewContainer>
    `;

    function testAction(views: Array<View>) {
        const page = <Page>views[1];
        waitUntilElementLayoutIsValid(page);
    };

    helper.buildUIAndRunTest(list, testAction);
}

// TODO: Proxy as a direct child to of TabItem is not supported. Not sure if we want to support it.
//export function test_proxy_inside_tab() {
//    const proxy = new ProxyViewContainer();
//    proxy.addChild(createBtn("1"));

//    const tab = new TabView();
//    const items = new Array<TabViewItem>();
//    items.push(new TabViewItem({ title: "tab with proxy", view: proxy }));
//    tab.items = items;

//    function testAction(views: Array<View>) {
//        const page = <Page>views[1];
//        waitUntilElementLayoutIsValid(page);
//    };

//    helper.buildUIAndRunTest(tab, tab);
//}

// TODO: Proxy as a direct child to of ActionBar is not supported. Not sure if we want to support it.
//export function test_proxy_inside_actionBar() {
//    function testAction(views: Array<View>) {
//        const page = <Page>views[1];
//        const proxy = new ProxyViewContainer();
//        proxy.addChild(createBtn("1"));
//        page.actionBar.titleView = proxy;
//        waitUntilElementLayoutIsValid(page);
//    };

//    helper.buildUIAndRunTest(createBtn("hi"), testAction);
//}

function waitUntilElementLayoutIsValid(view: View, timeoutSec?: number): void {
    TKUnit.waitUntilReady(() => {
        return view.isLayoutValid;
    }, timeoutSec || 1);
}

function createBtn(text: string): Button {
    const b = new Button();
    b.text = text;
    return b;
}

function assertNativeChildren(layout: LayoutBase, arr: Array<string>) {
    if (layout.android) {
        let android: org.nativescript.widgets.LayoutBase = layout.android;
        TKUnit.assertEqual(android.getChildCount(), arr.length, "Native children");
        for (let i = 0; i < arr.length; i++) {
            let nativeBtn = <android.widget.Button>android.getChildAt(i);
            TKUnit.assertEqual(nativeBtn.getText(), arr[i]);
        }
    } else if (layout.ios) {
        let ios: UIView = layout.ios;
        TKUnit.assertEqual(ios.subviews.count, arr.length, "Native children");
        for (let i = 0; i < arr.length; i++) {
            let nativeBtn = <UIButton>ios.subviews[i];
            TKUnit.assertEqual(nativeBtn.titleLabel.text, arr[i]);
        }
    } else {
        TKUnit.assert(false, "No native view to assert");
    }
}
