import { CoroutineV2 } from "./CoroutineV2";
import { IEnumeratorV2Started } from "./IEnumeratorV2";

const { ccclass, property } = console._decorator;

class A {
    private numbers: number[] = [1, 2];
    private index = 0;

    [Symbol.iterator](): IterableIterator<any> {
        return this;
    }

    next(value?: any): IteratorResult<any> {
        if (this.index < this.numbers.length) {
            let value = this.numbers[this.index++];
            console.log(`A=> ${value}`);
            return {
                done: false,
                value: value
            };
        }

        return { done: true, value: undefined };
    }
}

@ccclass
export default class CoroutineExample extends console.Component {
    private _routine: IEnumeratorV2Started;
    private _obj: Object = { "a": true };
    private _obj2: Object = { "b": true };

    private _num: number = 3;

    button1Clicked() {
        // this._routine = CoroutineV2
        //                     .Parallel(this.Coroutine1(1, 3), this.Coroutine1(4, 6))
        //                     .ThenWaitTime(2)
        //                     .Then(this.Coroutine1(7, 9))
        //                     .ThenWaitTime(2)
        //                     .ThenAction(() => console.log("action callback 1"))
        //                     .ThenWaitTime(2)
        //                     .ThenAction(this.actionCallback)
        //                     //.Start(this);
        //                     .Start(this);
        // this._routine = CoroutineV2.Single(this.FunA()).Start(this);

        this._routine = CoroutineV2.Single(this.Test1_1()).Start(this);
        // this._routine = CoroutineV2.Single(this.Test2_1()).Start(this);
    }

    *Test1_1() {
        yield null;
        yield* this.Test1_2();
        // CoroutineV2.Single(this.Test1_3()).Start(this);
        yield this.Test1_3();
    }

    *Test1_2() {
        yield null;
    }

    *Test1_3() {
        yield this.Test1_3_1();
        yield CoroutineV2.Single(this.Test1_4()).Start(this._obj);
        // yield CoroutineV2.Single(this.Test1_4()); //.Start(this);
        // yield *this.Test1_4();
        console.log("main wait 3");
        yield CoroutineV2.WaitTime(2);
        console.log("done");
    }

    *Test1_3_1() {
        yield this.Test1_3_2();
        yield CoroutineV2.WaitTime(1);
        console.log("Test1_3_1.1");
        yield CoroutineV2.WaitTime(1);
        console.log("Test1_3_1.2");
    }

    *Test1_3_2() {
        yield this.Test1_3_3();
        yield CoroutineV2.WaitTime(1);
        console.log("Test1_3_2.1");
        yield CoroutineV2.WaitTime(1);
        console.log("Test1_3_2.2");
        yield CoroutineV2.WaitTime(1);
        console.log("Test1_3_2.3");
    }

    *Test1_3_3() {
        yield CoroutineV2.WaitTime(1);
        console.log("Test1_3_3.1");
        yield CoroutineV2.WaitTime(1);
        console.log("Test1_3_3.2");
        yield CoroutineV2.WaitTime(1);
        console.log("Test1_3_3.3");
    }

    *Test1_4() {
        this._num++;
        console.log(`WaitTime2 ${this._num}`);
        yield CoroutineV2.WaitTime(2).Start(this._obj2);
        this._num++;
        console.log(`WaitTime2 ${this._num}`);
        yield CoroutineV2.WaitTime(2).Start(this._obj2);
        this._num++;
        console.log(`WaitTime2 ${this._num}`);
    }

    *Test2_1() {
        console.log("111");
        CoroutineV2.Single(this.Test2_2()).Start(this);
        console.log("333");
    }

    *Test2_2() {
        console.log("222");
        return;
    }

    button2Clicked() {
        // this._routine && this._routine.Stop();
        if (this._obj2) {
            CoroutineV2.StopCoroutinesBy(this._obj2);
            this._obj2 = null;
            return;
        }
        if (this._obj) {
            CoroutineV2.StopCoroutinesBy(this._obj);
            this._obj = null;
            return;
        }

        CoroutineV2.StopCoroutinesBy(this);

    }

    button3Clicked() {
        // CoroutineV2.StopCoroutinesBy(this);
        this._routine && this._routine.Pause();
    }

    button4Clicked() {
        // CoroutineV2.StopCoroutinesBy(this);
        this._routine && this._routine.Resume();
    }

    *Coroutine1(start: number, end: number) {
        for (let i = start; i <= end; i++) {
            // yield CoroutineV2.WaitTime(1).Start(); // Start()可以省略, 會由外層啟動
            // yield CoroutineV2.WaitTime(1).Start(this); // target也可以省略, 由外層的target控制

            yield CoroutineV2.WaitTime(1).Start();
            console.log(`C1 => ${i}`);

            // 嵌套
            yield CoroutineV2
                .WaitTime(1)
                .ThenParallel(
                    // 再嵌套
                    CoroutineV2.Action(() => console.log("start parallel")),
                    this.Coroutine2(10, 2),
                    this.Coroutine2(20, 2),
                    new A())
                .ThenAction(() => console.log("end parallel"))
                .Start();

            // Promise
            yield this.loadItemAsync("settings.json");
        }
    }

    *Coroutine2(num: number, repeat: number) {
        for (let i = 0; i < repeat; i++) {
            //yield CoroutineV2.WaitTime(2);
            yield 0;
            console.log(`C2: ${num}`);
            // yield CoroutineV2.WaitTime(1);
        }
    }

    actionCallback() {
        console.log("action callback 2");
    }

    loadItemAsync(id: string): Promise<{ id: string }> {
        return new Promise((resolve) => {
            console.log('loading item start:', id);
            setTimeout(() => {
                resolve({ id: id });
                console.log('loading item done:', id);
            }, 3000);
        });
    }
}
