import Locator from '../../../services/Locator';
import { PaneExtended } from '../interfaces/PaneExtended';

/**
 * The `UserControls` class in TypeScript manages user controls for server URL, shared player, custom
 * player, and user switching with options stored in local storage.
 */
export class UserControls
{
    static controlName = 'UserControls';
    pane: PaneExtended;
    serverURLBlade: any;
    sharedPlayerBlade: any;
    currencyBlade: any;
    serverURL: any;

    /**
     * The constructor function takes a PaneExtended parameter and assigns it to the instance variable
     * pane.
     * @param {PaneExtended} pane - The `pane` parameter in the constructor is of type `PaneExtended`.
     */
    constructor(pane: PaneExtended)
    {
        this.pane = pane;
    }

    /**
     * The `initialize` function sets user type based on localStorage options and adds various inputs
     * and buttons to a folder in the UI.
     */
    async initialize()
    {
        const userType = 'Master'; // from index.html

        const folder = this.pane.addFolder({ title: `Player - ${userType} selected`, expanded: false });

        if (Locator.network.name === 'MockNetwork') return;

        if (!this.pane.settings.users)
        {
            this.pane.settings = {
                users: {
                    serverURL: 'dev.popiplay.dev',
                    sharedPlayer: '1',
                    currency: 'EUR'
                }
            };
        }

        if (this.pane.settings.users.serverURL)
        {
            let url = this.pane.settings.users.serverURL.replace(/^https?:\/\//, '');

            url = url.replace(/\/+$/, '');
            this.pane.settings = {
                users: {
                    serverURL: url,
                    sharedPlayer: this.pane.settings.users.sharedPlayer ?? '1',
                    currency: this.pane.settings.users.currency ?? 'EUR'
                }
            };
        }

        await this.addServerAndSharedUserInputs(folder);
        this.addReloadToSharedUserBtn(folder);
        this.addChangeUserBtn(folder);
    }

    /**
     * The function `addServerAndSharedUserInputs` adds input fields for server URL and shared player to
     * a given folder.
     * @param folder - The `folder` parameter in the `addServerAndSharedUserInputs` function is used to
     * specify the folder where the input elements (blades) for server URL and shared player will be
     * added. These input elements allow users to input the server URL and shared player information,
     * which are then stored in
     */
    async addServerAndSharedUserInputs(folder: any)
    {
        this.serverURLBlade = folder.addBlade({
            view: 'text',
            label: 'Server URL:',
            parse: (v: any) => String(v),
            value: this.pane.settings.users?.serverURL || 'dev.popiplay.dev',
        });

        this.addServerURLUpdateButton(folder);

        this.serverURLBlade.on('change', (e: { value: any; }) =>
        {
            this.pane.settings = { users: { ...this.pane.settings.users, serverURL: e.value } };
        });

        this.serverURL = this.serverURLBlade.value || (window as any).__OPTIONS__.games_page_url || 'https://dev.popiplay.dev';

        this.sharedPlayerBlade = folder.addBlade({
            view: 'text',
            label: 'Shared Player:',
            parse: (v: any) => String(v),
            value: this.pane.settings.users?.sharedPlayer || '-1',
        });
        this.sharedPlayerBlade.on('change', (e: { value: any; }) =>
        {
            this.pane.settings = { users: { ...this.pane.settings.users, sharedPlayer: e.value } };
        });

        const availableCurrencies = await this.getAvailableCurrencies();

        this.currencyBlade = folder.addBlade({
            view: 'list',
            label: 'Currency:',
            options: availableCurrencies,
            value: this.pane.settings.users?.currency || 'EUR',
        });

        if (!this.pane.settings.users.currency) this.pane.settings.users.currency = 'EUR';

        this.currencyBlade.on('change', (e: { value: any; }) =>
        {
            this.pane.settings = { users: { ...this.pane.settings.users, currency: e.value } };
        });
    }

    async getAvailableCurrencies(): Promise<any[]>
    {
        const response = await fetch(`https://${this.serverURL}/api/app/devdemo/catalog.json`, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json'
            }
        });

        const data = await response.json();

        const game = data.games.find((el: any) => el.id === (window as any).__OPTIONS__.identifier);

        return game?.currencies
            ? game?.currencies.map((currency: any) =>
                ({ text: currency, value: currency }))
            : [];
    }

    addServerURLUpdateButton(folder: any)
    {
        const addServerURLUpdateButton = folder.addButton({ title: 'Update Server URL' });

        addServerURLUpdateButton.on('click', () => location.reload());
    }

    /**
     * The function `addReloadToSharedUserBtn` adds a button to a folder that, when clicked, triggers a
     * method to get shared user options.
     * @param folder - An object representing a folder in the application.
     */
    addReloadToSharedUserBtn(folder: any)
    {
        const reloadToSharedUserBtn = folder.addButton({ title: 'Reload to Shared Player' });

        reloadToSharedUserBtn.on('click', this.getSharedPlayerApiUrl.bind(this));
    }

    async getSharedPlayerApiUrl()
    {
        const responseWithPlayer = await fetch(`https://${this.serverURL}/api/app/devdemo/catalog.json`, {
            method: 'GET',
            headers: {
                'Content-Type': 'application/json',
            }
        });
        const parsedResponseWithPlayer = await responseWithPlayer.json();
        const player = parsedResponseWithPlayer.shared_players.find(
            (player: { id: number; }) => player.id === Number(this.sharedPlayerBlade.value)
        );

        if (!player)
        {
            console.warn(`No Shared Player ${this.sharedPlayerBlade.value}!`);

            return;
        }
        const sharedPlayerToken: string = await this.getSharedUser(player.player_id);

        if (sharedPlayerToken)
        {
            localStorage.setItem('shared_user_api_url', sharedPlayerToken);
            location.reload();
        }
        else
        {
            console.warn('Shared Player Token was not found');
        }
    }

    /**
     * The function adds a button to a folder that, when clicked, triggers a user change action.
     * @param folder - The `folder` parameter is likely an object representing a folder or directory in a
     * file system or a similar hierarchical structure. It seems to have a method `addButton` that can be
     * used to create a button within this folder.
     */
    addChangeUserBtn(folder: any)
    {
        const changeUserBtn = folder.addButton({ title: 'Choose Random Player and Reload' });

        changeUserBtn.on('click', this.changeUser.bind(this));
    }

    async getSharedUser(playerId: string): Promise<string>
    {
        try
        {
            // TODO: check if it's gonna work on dev.popiplay.dev
            document.cookie = `devdemo_player_id=${playerId}; path=/`;
            document.cookie = `proxy_target=${encodeURIComponent(this.pane.settings.users.serverURL)}; path=/`;
            let origin;

            if (window.location.hostname === 'localhost')
            {
                origin = `${window.location.protocol}//${window.location.hostname}:${window.location.port}/proxy`;
            }
            else
            {
                origin = this.serverURL;
            }
            const currency = this.pane.settings.users?.currency;
            const link = `${origin}/s/devdemo/compatibility/play/${(window as any).__OPTIONS__.identifier}/${currency}?locale=en&server_url=https://static.popiplay.dev/html/`;

            return fetch(link, {
                method: 'GET',
                credentials: 'include',
            }).then((d) => d.text())
                .then((data: string): string | null =>
                {
                    const doc = new DOMParser().parseFromString(data, 'text/html');
                    const scripts = Array.from(doc.scripts);
                    const apiRegex = /"api":"(.*?)"/;

                    const match = scripts
                        .map((script) => script.textContent?.match(apiRegex)?.[1])
                        .find(Boolean);

                    return match ?? null;
                });
        }
        catch (error)
        {
            console.warn('error:', error);

            return null;
        }
    }

    async getRandomUser(playerId: string)
    {
        try
        {
            const currency = this.pane.settings.users?.currency;
            const url = `https://${this.serverURL}/s/devdemo/compatibility/play/${(window as any).__OPTIONS__.identifier}/${currency}?locale=en&server_url=https://static.popiplay.dev/html/`;

            return fetch(url, {
                method: 'GET',
                headers: {
                    'Content-Type': 'application/json',
                    Cookie: `devdemo_player_id=${playerId}`
                },
            }).then((d) => d.text())
                .then((data: string): string | null =>
                {
                    const doc = new DOMParser().parseFromString(data, 'text/html');
                    const scripts = Array.from(doc.scripts);
                    const apiRegex = /"api":"(.*?)"/;

                    const match = scripts
                        .map((script) => script.textContent?.match(apiRegex)?.[1])
                        .find(Boolean);

                    return match ?? null;
                });
        }
        catch (error)
        {
            return console.warn('error:', error);
        }
    }

    async changeUser()
    {
        const sharedPlayerToken: any = await this.getRandomUser('');

        if (sharedPlayerToken)
        {
            localStorage.setItem('shared_user_api_url', sharedPlayerToken);
            location.reload();
        }
    }
}
