import { Apps, FILENAME, Tokens } from './constants';
import LocalazyApi from '@localazy/ts-api';
import { Key } from '@localazy/ts-api/dist/models/responses/keys-in-file';
import { get, set } from './utils';
import * as fs from 'fs';

export class LocalazyRunner {
    private readonly _api;
    private _projectId = '';
    private _fileId = '';

    constructor(readonly app: Apps) {
        this._api = LocalazyApi({
            projectToken: Tokens[app],
            baseUrl: 'https://api.localazy.com',
        });
    }

    async initialize(): Promise<void> {
        this._projectId = await this._getProjectId();
        this._fileId = await this._getFileId();
    }

    async synchronize(): Promise<void> {
        /** Update local en (source) file with potential remotely updated translations. */
        const remoteKeys = await this._listKeys('en');
        await this._updateLocalEn(remoteKeys);

        /** Upload local en (source) file in order to add new keys and deprecate unused keys. */
        await this._uploadLocal('en');

        /** Download updated de file. */
        await this._updateLocalDe();
    }

    /** For debug purposes only. */
    async uploadLocalDe() {
        await this._uploadLocal('de');
    }

    /** For debug purposes only. */
    async downloadDe() {
        console.log(await this._downloadLanguage('de'));
    }

    private async _uploadLocal(lang: 'en' | 'de'): Promise<void> {
        const langFile = (await import(`./../../../apps/red-ui/src/assets/i18n/${this.app}/${lang}.json`)).default;

        await this._api.import({
            projectId: this._projectId,
            files: [
                {
                    name: FILENAME,
                    content: { type: 'json', features: ['plural_icu', 'filter_untranslated'], [lang]: langFile },
                },
            ],
            deprecate: 'project',
        });
    }

    private async _listKeys(lang: 'en' | 'de'): Promise<Key[]> {
        let keys: Key[] = [];
        let next: string | undefined = undefined;
        do {
            const response = await this._api.listKeysInFileForLanguage({ projectId: this._projectId, fileId: this._fileId, lang, next });
            next = response.next;
            keys = [...keys, ...response.keys];
        } while (next);
        return keys;
    }

    private async _updateLocalEn(keys: Key[]): Promise<void> {
        const enFile = (await import(`./../../../apps/red-ui/src/assets/i18n/${this.app}/en.json`)).default;

        keys.forEach(({ key, value }) => {
            if (get(enFile, key) !== undefined) {
                set(enFile, key, value);
            }
        });

        await fs.promises.writeFile(`./../../apps/red-ui/src/assets/i18n/${this.app}/en.json`, JSON.stringify(enFile, null, 2));
    }

    private async _updateLocalDe(): Promise<void> {
        const deFile = await this._downloadLanguage('de');
        await fs.promises.writeFile(`./../../apps/red-ui/src/assets/i18n/${this.app}/de.json`, JSON.stringify(deFile, null, 2));
    }

    private async _downloadLanguage(lang: 'en' | 'de'): Promise<any> {
        const response = await this._api.getFileContents({ projectId: this._projectId, fileId: this._fileId, lang });
        return JSON.parse(await response.text());
    }

    private async _getProjectId(): Promise<string> {
        const projects = await this._api.listProjects();
        return projects[0].id;
    }

    private async _getFileId(): Promise<string> {
        const files = await this._api.listFiles({ projectId: this._projectId });
        return files.find(file => file.name === FILENAME)!.id;
    }
}
