<template>
    <div class="app-custom-theme" @click="showDrawer = true">
        <span>
            <icon class='app-theme-icon' :title="$t('components.apptheme.config')" type='md-settings' :size="15" />
        </span>
        <span class="title">
            {{$t('components.apptheme.config')}}
        </span>
        <el-drawer append-to-body :title="$t('components.apptheme.customtheme')" :show-close="true"
            :visible.sync="showDrawer" :with-header="false" custom-class="app-custom-theme__drawer" @open="drawerOpen">
            <div class="app-custom-theme__color">
                <h3>{{$t('components.apptheme.color')}}</h3>
                <span v-for="(theme, index) in defaultThemes" :key="index" :class="{ 
                    'color-item': true,
                    [theme.codeName]: true,
                    'is-active': selectTheme && selectTheme == theme.codeName ? true : false
                }" :title="theme.title" :style="{ 'background-color': theme.color }"
                    @click="themeChange(theme.codeName)"/>
            </div>
            <div class="app-custom-theme__split"></div>
            <div class="app-custom-theme__theme-vars">
                <template v-for="(type, index) in themeTypes" >
                    <div class="theme-vars-group" v-if="!type.disabled" :key="type.value">
                        <span class="theme-vars-group__title">{{ type.label }}</span>
                        <div class="theme-vars-group__items">
                            <template v-for="(item, index) in type.items">
                                <div v-if="!item.disabled" :key="index" class="theme-vars-item">
                                    <span class="theme-vars-item__title">{{ item.label }}</span>
                                    <el-color-picker v-model="themeOptions[item.cssName]" :show-alpha="item.showAlpha" size="small" />
                                </div>
                            </template>
                            <div v-if="type.value === 'other' && fontsFamily && fontsFamily.length > 0" class="theme-vars-item theme-vars-item__font">
                                <span class="theme-vars-item__title">{{ $t('components.apptheme.caption.font') }}</span>
                                <el-select v-model="selectFont" size="small">
                                    <el-option v-for="font in fontsFamily" :key="font.value"
                                        :label="$t(`components.apptheme.fontfamilys.${font.label}`)"
                                        :value="font.value">
                                        <span :style="{ fontFamily: font.value }">{{$t(`components.apptheme.fontfamilys.${font.label}`)}}</span>
                                    </el-option>
                                </el-select>
                            </div>
                        </div>
                    </div>
                    <div v-if="!type.disabled && index < themeTypes.length" class="app-custom-theme__split" :key="index"></div>
                </template>
            </div>
            <div class="app-custom-theme__buttons">
                <app-button class="preview" @onClick="previewTheme">{{$t('components.apptheme.preview')}}</app-button>
                <app-button @onClick="saveThemeOptions">{{$t('components.apptheme.save')}}</app-button>
                <app-button @onClick="reset">{{$t('components.apptheme.reset')}}</app-button>
                <app-button @onClick="share">{{$t('components.apptheme.share')}}</app-button>
            </div>
        </el-drawer>
    </div>
</template>

<script lang="ts">
import { Vue, Component, Prop } from 'vue-property-decorator';
import { themeConfig, fontsConfig } from '@/config/themeConfig';
import { appConfig } from '@/config/appConfig';
import { AppServiceBase, textCopy } from 'ibiz-core';
import qs from 'qs';

@Component({})
export default class AppCustomTheme extends Vue {

    /**
     * 视图样式
     * 
     * @type {string}
     * @memberof AppCustomTheme
     */
    @Prop({ default: 'DEFAULT' }) public viewStyle!: string;

    /**
     * 系统-应用标识
     * 
     * @type {string}
     * @memberof AppCustomTheme
     */
    public AppTag: any;

    /**
     * 主题配置标识
     * 
     * @type {string}
     * @memberof AppCustomTheme
     */
    public themeOptionId: string = '';

    /**
     * 主题css变量配置
     * 
     * @type {string}
     * @memberof AppCustomTheme
     */
    public themeTypes: Array<any> = [];

    /**
     * 默认样式集合
     * 
     * @type {any[]}
     * @memberof AppCustomTheme
     */
    public defaultThemes: any[] = [];

    /**
     * 默认字体集合
     * 
     * @type {any[]}
     * @memberof AppCustomTheme
     */
    public fontsFamily: any[] = fontsConfig;

    /**
     * 环境配置
     * 
     * @type {any}
     * @memberof AppCustomTheme
     */
    public Environment: any = AppServiceBase.getInstance().getAppEnvironment();

    /**
     * 当前选中样式
     * 
     * @type {string}
     * @memberof AppCustomTheme
     */
    public selectTheme: string = '';

    /**
     * 当前选中字体
     * 
     * @type {any}
     * @memberof AppCustomTheme
     */
    public selectFont: any = {};

    /**
     * 是否显示抽屉
     * 
     * @type {boolean}
     * @memberof AppCustomTheme
     */
    public showDrawer: boolean = false;

    /**
     * 当前激活分页
     * 
     * @type {string}
     * @memberof AppCustomTheme
     */
    public activeSetting: string = '';

    /**
     * 主题配置
     * 
     * @type {any}
     * @memberof AppCustomTheme
     */
    public themeOptions: any = {};

    /**
     * 状态管理对象
     * 
     * @type {any}
     * @memberof AppCustomTheme
     */
    public store: any;

    /**
     * vue生命周期 -- created
     * 
     * @memberof AppCustomTheme
     */
    public created() {
        this.store = AppServiceBase.getInstance().getAppStore();
        this.AppTag = `${this.Environment.SysName}-${this.Environment.AppName}`;
        this.selectTheme = this.getSelectTheme();
        this.selectFont = this.getSelectFont();
        this.init();
        this.applyLess();
    }

    /**
     * 初始化
     * 
     * @memberof AppCustomTheme
     */
    private init(reload: boolean = true) {
        if (themeConfig && themeConfig.length > 0) {
            const themeTypes: string[] = [];
            themeConfig.forEach((theme: any) => {
                if (!theme.disabled) {
                    themeTypes.push(theme);
                    if (theme.codeName === this.selectTheme) {
                        this.themeTypes = theme.vars;
                        this.activeSetting = theme.vars[0].value;
                        this.initDefaultOptions(theme.vars, reload);
                    }
                }
            });
            this.$set(this, 'defaultThemes', themeTypes);
        }
    }

    /**
     * 初始化默认配置
     * 
     * @memberof AppCustomTheme
     */
    private initDefaultOptions(cssVars: any[], reload: boolean = true) {
        if (!cssVars || cssVars.length === 0) {
            return;
        }
        const themeOptions: any = {};
        cssVars.forEach((item: any) => {
            if (!item.disabled && item.items && item.items.length > 0) {
                item.items.forEach((child: any) => {
                    if (reload) {
                        if (child.default) {
                            Object.assign(themeOptions, { [child.cssName]: child.default });
                        }
                    } else {
                        if (this.themeOptions && this.themeOptions.hasOwnProperty(child.cssName)) {
                            Object.assign(themeOptions, { [child.cssName]: this.themeOptions[child.cssName] });
                        }
                    }
                })
            }
        });
        this.$set(this, 'themeOptions', themeOptions);
    }

    /**
     * 获取分享主题配置
     * 
     * @memberof AppCustomTheme
     */
    public async getShareThemeOptions(themeOptionId: any) {
        try {
            const res = await this.$http.get(`/configs/share/${themeOptionId}`);
            if (res.status == 200 && res.data && res.data.model) {
                return res.data.model;
            } else {
                return null;
            }
        } catch (error: any) {
            this.$throw(this.$t('components.apptheme.error.getshareurl'));
            return null;
        }
    }

    /**
     * 获取选中主题
     * 
     * @memberof AppCustomTheme
     */
    private getSelectTheme() {
        if (this.store && this.store.state && this.store.state.selectTheme) {
            return this.store.state.selectTheme;
        } else if (localStorage.getItem('theme-class')) {
            return localStorage.getItem('theme-class');
        } else {
            return appConfig.defaultTheme || 'app-theme-default';
        }
    }

    /**
     * 获取选中字体
     * 
     * @memberof AppCustomTheme
     */
    private getSelectFont() {
        if (localStorage.getItem('font-family')) {
            return localStorage.getItem('font-family');
        }
        return appConfig.defaultFont || 'Microsoft YaHei';
    }

    /**
     * 处理主题配置
     * 
     * @memberof AppCustomTheme
     */
    public handleThemeOptions() {
        this.init(false);
    }

    /**
     * 切换主题
     * 
     * @memberof AppCustomTheme
     */
    public themeChange(tag: string) {
        if (tag && this.selectTheme != tag) {
            this.selectTheme = tag;
            this.init(true);
        }
    }

    /**
     * 主题应用
     * 
     * @memberof AppCustomTheme
     */
    public previewTheme() {
        this.applyLess();
    }

    /**
     * 应用less变量
     * 
     * @memberof AppCustomTheme
     */
    private applyLess() {
        const less: any = (window as any).less;
        if (!less) {
            return;
        }
        less.modifyVars(this.getVars()).then((res: any) => {
            localStorage.setItem('theme-class', this.selectTheme);
            localStorage.setItem('font-family', this.selectFont);
            if (this.store) {
                this.store.commit('setCurrentSelectTheme', this.selectTheme);
            }
        })
    }

    /**
     * 获取变量
     * 
     * @memberof AppCustomTheme
     */
    private getVars(): any {
        const select = this.defaultThemes.find((item: any) => item.codeName === this.selectTheme);
        const vars = {
            "@primary": select.color,
            "@font-family": this.selectFont
        };
        if (this.themeOptions && Object.keys(this.themeOptions).length > 0) {
            Object.keys(this.themeOptions).forEach((key: string) => {
                Object.assign(vars, { [`@${key}`]: this.themeOptions[key] });
            })
        }
        return vars;
    }

    /**
     * 抽屉打开回调
     * 
     * @memberof AppCustomTheme
     */
    public drawerOpen() {
        this.selectTheme = this.getSelectTheme();
        const themeOptions = localStorage.getItem(`${this.AppTag}-theme-options`);
        if (themeOptions) {
            this.themeOptions = JSON.parse(themeOptions);
        } else {
            this.init(false);
        }
    }

    /**
     * 保存主题配置
     * 
     * @memberof AppCustomTheme
     */
    public saveThemeOptions(isShare: boolean = false) {
        if (this.themeOptions) {
            this.$http.put(`/configs/${this.AppTag}/theme-setting`,
                { model: { cssValue: JSON.stringify(this.themeOptions), fontFamily: this.selectFont } }).then((res: any) => {
                    if (res) {
                        const _this: any = this;
                        _this.$success(isShare ? this.$t('components.apptheme.applytheme') : this.$t('components.apptheme.success.savethemeoption'));
                        this.previewTheme();
                    }
                });
        }
    }

    /**
     * 重置主题配置
     * 
     * @memberof AppCustomTheme
     */
    public reset() {
        if (this.selectTheme) {
            this.init();
        }
    }

    /**
     * 分享主题
     * 
     * @memberof AppCustomTheme
     */
    public share() {
        this.saveThemeOptions();
        try {
            this.$http.get(`/configs/share/${this.AppTag}/theme-setting`).then((res: any) => {
                if (res.status == 200 && res.data) {
                    const shareUrl = this.generateShareUrl(res.data);
                    const _this: any = this;
                    const h = this.$createElement('el-input', {
                        props: {
                            value: shareUrl,
                            disabled: true,
                            size: 'small'
                        }
                    })
                    _this.$alert(h, this.$t('components.apptheme.createurl'), {
                        confirmButtonText: this.$t('components.apptheme.configbutton'),
                        customClass: 'share-theme-box',
                        callback: (action: any) => {
                            _this.copyShareUrl(action, shareUrl);
                        }
                    })
                } else {
                    this.$throw(this.$t('components.apptheme.error.generateshareurl'));
                }
            })
        } catch (error: any) {
            this.$throw(this.$t('components.apptheme.error.generateshareurl'));
        }
    }

    /**
     * 生成分享链接
     * 
     * @memberof AppCustomTheme
     */
    public generateShareUrl(themeOptionId: any) {
        const href: string = window.location.href;
        const userName = this.$store.getters.getAppData().context?.srfusername;
        const baseStr = window.btoa(`applyThemeOption=true&themeOptionId=${themeOptionId}`);
        const param = `#/appsharepage?theme=${baseStr}&shareUserName=${encodeURIComponent(userName)}`;
        return href.replace(/#\/\S*/, param);
    }

    /**
     * 拷贝分享链接
     * 
     * @memberof AppCustomTheme
     */
    public copyShareUrl(action: string, shareUrl: any) {
        if (action == 'cancel') {
            return;
        }
        textCopy.copy(shareUrl);
        this.$success(this.$t('components.apptheme.success.copyurl'), 'saveShareThemeUrlSuccess');
    }

    /**
     * 处理链接参数
     * 
     * @memberof AppCustomTheme
     */
    public parseViewParam(urlStr: string): any {
        let tempViewParam: any = {};
        const tempViewparam: any = urlStr.slice(urlStr.lastIndexOf('?') + 1);
        const viewparamArray: Array<string> = decodeURIComponent(tempViewparam).split(';');
        if (viewparamArray.length > 0) {
            viewparamArray.forEach((item: any) => {
                Object.assign(tempViewParam, qs.parse(item));
            });
        }
        return tempViewParam;
    }

    /**
     * 是否是分享链接打开
     * 
     * @memberof AppCustomTheme
     */
    public isShare(): boolean {
        const urlParams = this.parseViewParam(window.location.href);
        if (Object.keys(urlParams).length == 0) {
            return false;
        }
        if (urlParams.hasOwnProperty('theme') && urlParams['theme']) {
            try {
                const tempParam: any = this.parseViewParam(window.atob(urlParams['theme']));
                if (tempParam.hasOwnProperty('applyThemeOption')
                    && tempParam['applyThemeOption'] == 'true'
                    && tempParam.hasOwnProperty('themeOptionId')
                    && tempParam['themeOptionId'] != ''
                    && tempParam['themeOptionId'] != null) {
                    this.themeOptionId = tempParam['themeOptionId'];
                    return true;
                }
            } catch (error: any) {
                return false;
            }
        }
        return false;
    }

    /**
     * vue生命周期 -- destroyed
     * 
     * @memberof AppCustomTheme
     */
    public destroyed() {
        localStorage.removeItem(`${this.AppTag}-theme-options`);
    }

}

</script>