import dayjs from "dayjs";
import { Ref, ref } from "vue";
import CSMessage from "./Base/CSMessage";
import { AccountLoginRequest, CustomLoginRequest } from "./Base/Request/AccountRequest";
import { BJ_Casino_Bot_Lobby } from "./BJ_Casino_Bot_Lobby";
import { BJ_Casino_Bot_Login } from "./BJ_Casino_Bot_Login";
import { BJ_Casino_Bot_Slot } from "./BJ_Casino_Bot_Slot";
import { BJ_Casino_UserData } from "./BJ_Casino_Userdata";
import { INetResponse } from "./Engine/CatanEngine/NetManagerV2/Core/INetResponse";
import { NetConnector } from "./Engine/CatanEngine/NetManagerV2/NetConnector";
import { NetManager } from "./Engine/CatanEngine/NetManagerV2/NetManager";
import { Tools } from "./Tools";

export class BJ_Casino_Bot {
    //#region public

    public UserData: BJ_Casino_UserData = null;

    public LoginScript: BJ_Casino_Bot_Login = null;

    public LobbyScript: BJ_Casino_Bot_Lobby = null;

    public SlotScript: BJ_Casino_Bot_Slot = null;

    // Login
    public IsLogin: Ref<boolean> = ref(false);

    // Info
    public AID: Ref<string> = ref("");
    public NickName: Ref<string> = ref("");
    public Money: Ref<number> = ref(0);
    public Level: Ref<number> = ref(0);
    public Exp: Ref<number> = ref(0);

    // Lobby
    public LobbyShow: Ref<boolean> = ref(false);

    // Slot
    public SlotShow: Ref<boolean> = ref(false);

    // Log
    public Log: Ref<string> = ref("");

    //#endregion

    //#region private

    private _client: any;

    private _conn: NetConnector = null;

    //#endregion

    //#region Lifecycle

    /**
     *
     */
    constructor(client: any) {
        this._client = client;
        this.onLoad();
    }

    public async onLoad(): Promise<void> {
        // await this._login();
    }

    //#endregion

    //#region Custom

    public async Login(a: string, p: string): Promise<void> {
        let self: this = this;
        // const URL: string = "https://game.online-bj.com";
        // const Port: string = "9005";
        const URL: string = "http://220.134.195.1";
        const Port: string = "19005";
        await this.ConnectAsync(URL, +Port);
        // 取得帳號資料
        let resp: any = await this._accountLogin(a, p);
        await this._getAccountInfo(resp.a, resp.pw);
        this.IsLogin.value = true;
        this.LobbyShow.value = true;
        this.SetUI();
    }

    public async Logout(): Promise<void> {
        NetManager.Disconnect();
        this.IsLogin.value = false;
        this.LobbyShow.value = false;
    }

    private async _accountLogin(account: string, password: string): Promise<any> {
        let req: CustomLoginRequest = new CustomLoginRequest(account, password);
        await req.SendAsync(true);
        let resp: INetResponse<any> = req.Result;
        if (!resp.IsValid) {
            CSMessage.NetError(resp.Method, resp.Status, "Registe Account Error!");
            return;
        }
        return resp.Data;
    }

    private async _getAccountInfo(a: string, pw: string): Promise<void> {
        // 取得帳號資料
        let req: AccountLoginRequest = new AccountLoginRequest(a, pw);
        await req.SendAsync(true);
        let resp: INetResponse<any> = req.Result;
        if (!resp.IsValid) {
            CSMessage.NetError(resp.Method, resp.Status, "Login Account Error!");
            return;
        }
        this.UserData = new BJ_Casino_UserData(resp.Data["id"].toString(), resp.Data["name"].toString(), +resp.Data["m"], +resp.Data["lv"], +resp.Data["exp"]);
    }

    public SetUI(): void {
        this.AID.value = this.UserData.AID;
        this.NickName.value = this.UserData.NickName;
        this.Money.value = this.UserData.Money;
        this.Level.value = this.UserData.Level;
        this.Exp.value = this.UserData.Exp;
    }

    public AddLog(log: string): void {
        let AIDLog: string = ``;
        if (this.UserData?.AID) {
            AIDLog = `AID: ${this.UserData.AID} `;
        }
        console.log(`${AIDLog}${log}`);
        let time: string = dayjs().format("YYYY/MM/DD HH:mm:ss.SSS");
        this.Log.value += `${time} ${log}\n`;
        const textarea: HTMLElement | null = document.getElementById("DIV_LOG");
        if (textarea) {
            textarea.scrollTop = textarea.scrollHeight;
        }
    }

    //#endregion

    //#region Onclick

    //#endregion

    //#region 網路相關

    /** 連線(目前沒有重連機制) */
    public async ConnectAsync(host: string, port: number): Promise<void> {
        var url: string = "https://api.ipify.org/?format=json";
        var xhr: XMLHttpRequest = new XMLHttpRequest();
        let ip: string = "";
        xhr.onreadystatechange = function (): void {
            if (xhr.readyState === 4 && (xhr.status >= 200 && xhr.status < 400)) {
                ip = JSON.parse(xhr.responseText)["ip"];
            }
        };
        xhr.open("GET", url, true);
        xhr.send();
        this.AddLog("[事件]準備連線...");
        while (ip === "") {
            await Tools.Sleep(1);
        }
        this._conn = new NetConnector(host, port, ip);
        this._conn.OnDataReceived.AddCallback(this._onNetDataReceived, this);
        this._conn.OnDisconnected.AddCallback(this._onNetDisconnected, this);
        NetManager.Initialize(this._conn);
        this.AddLog("[事件]連線中...");
        // 同個connector要再次連線, 可以不用叫CasinoNetManager.Initialize(), 但要先叫CasinoNetManager.Disconnect()
        await NetManager.ConnectAsync();
        this.AddLog(String.Format("[事件]連線狀態: {0}", NetManager.IsConnected));
    }

    private _onNetDisconnected(): void {
        this.AddLog("[事件] 收到連線中斷事件");
        this._conn.OnDataReceived.RemoveAllCallbacks();
        // MainControl.DataReceivedEvent.DispatchCallback([MainControl.DataType.NetDisconnected]);
    }

    private _onNetDataReceived(resp: INetResponse<any>): void {
        let AIDLog: string = ``;
        if (this.UserData?.AID) {
            AIDLog = `AID: ${this.UserData.AID} `;
        }
        console.log(`${AIDLog}[事件] 收到server呼叫: ${resp.Method}(${JSON.stringify(resp.Data)}), 狀態: ${resp.Status}`);
        // MainControl.DataReceivedEvent.DispatchCallback([MainControl.DataType.ServerData, resp]);
    }

    //#endregion
}
