<template>
    <div id="danmaku-editor" @click.stop>
        <div id="danmaku-input">
            <span
                class="danmaku-tool"
                :open="cssOpened"
                @click="openTool('css')"
                >css</span
            >
            <font-colors-outlined
                class="danmaku-tool"
                :open="fillOpened"
                @click="openTool('fillColor')"
            />
            <highlight-outlined
                class="danmaku-tool"
                :open="strokeOpened"
                @click="openTool('strokeColor')"
            />
            <meh-outlined
                class="danmaku-tool"
                :open="iconOpened"
                @click="openTool('icon')"
            />
            <div id="danmaku-input-div">
                <a-input
                    id="danmaku-input-input"
                    :max-length="200"
                    v-model:value="inputValue"
                    placeholder="请在此输入弹幕"
                    autocomplete="off"
                    @change="input(inputValue)"
                    @pressEnter="inputEnter()"
                />
            </div>
            <send-outlined
                class="danmaku-tool danmaku-post"
                :posting="posting"
                @click="send()"
            />
        </div>
        <Transition name="danmaku">
            <div v-if="cssOpened" id="danmaku-css">
                <span id="danmaku-css-hint">编辑弹幕的 CSS 样式</span>
                <a-input
                    id="danmaku-css-input"
                    :max-length="300"
                    v-model:value="cssInfo"
                    placeholder="请在此输入样式"
                    autocomplete="off"
                    @blur="inputCSS(cssInfo)"
                    @pressEnter="inputCSS(cssInfo)"
                />
                <span v-if="cssError" id="danmaku-css-error">{{
                    cssError
                }}</span>
            </div>
            <div v-else-if="iconOpened" id="danmaku-icon">
                <span id="danmaku-icon-hint">常用图标</span>
                <Scroll
                    class="danmaku-icon-scroll"
                    :no-scroll="true"
                    type="horizontal"
                >
                    <div id="danmaku-icon-div">
                        <span
                            class="danmaku-icon-one"
                            v-for="icon of frequentlyIcon"
                            @click="addIcon(icon as AllIds)"
                        >
                            <BoxAnimate
                                :id="(icon as AllIds)"
                                :noborder="true"
                                :no-animate="true"
                                :height="getIconHeight(icon as AllIds)"
                            ></BoxAnimate>
                        </span>
                    </div>
                </Scroll>
                <span
                    id="danmaku-icon-all"
                    class="button-text"
                    :active="iconAll"
                    @click="iconAll = !iconAll"
                >
                    所有图标 <up-outlined />
                </span>
            </div>
            <div v-else-if="fillOpened || strokeOpened" id="danmaku-color">
                <span id="danmaku-color-hint">设置颜色</span>
                <Scroll
                    class="danmaku-color-scroll"
                    :no-scroll="true"
                    type="horizontal"
                >
                    <div id="danmaku-color-container">
                        <span
                            v-for="color of frequentlyColor"
                            :style="{ backgroundColor: color }"
                            :selected="color === nowColor"
                            @click="inputColor(color)"
                            class="danmaku-color-one"
                        ></span>
                    </div>
                </Scroll>
                <a-input
                    id="danmaku-color-input"
                    :max-length="100"
                    v-model:value="nowColor"
                    placeholder="输入颜色"
                    autocomplete="off"
                    @blur="inputColor(nowColor)"
                    @pressEnter="inputColor(nowColor)"
                ></a-input>
            </div>
        </Transition>
        <Transition name="danmaku-icon">
            <div v-if="iconAll" id="danmaku-icon-all-div">
                <span
                    >本列表不包含额外素材，如果需要额外素材请手动填写素材id</span
                >
                <Scroll class="danmaku-all-scroll">
                    <div id="danmaku-all-container">
                        <span
                            v-for="icon of getAllIcons()"
                            @click="addIcon(icon)"
                        >
                            <BoxAnimate
                                :id="icon"
                                :height="getIconHeight(icon)"
                                :no-animate="true"
                                :noborder="true"
                            ></BoxAnimate>
                        </span>
                    </div>
                </Scroll>
            </div>
        </Transition>
    </div>
</template>

<script lang="ts" setup>
import { Ref, onMounted, onUnmounted, ref } from 'vue';
import {
    FontColorsOutlined,
    HighlightOutlined,
    MehOutlined,
    SendOutlined,
    UpOutlined
} from '@ant-design/icons-vue';
import { Danmaku } from '@/core/main/custom/danmaku';
import { GameUi } from '@/core/main/custom/ui';
import { sleep } from 'mutate-animate';
import { fixedUi } from '@/core/main/init/ui';
import { tip } from '@/plugin/utils';
import { gameKey } from '@/core/main/init/hotkey';
import { isNil } from 'lodash-es';
import { stringifyCSS, parseCss, getIconHeight } from '@/plugin/utils';
import { logger, LogLevel } from '@/core/common/logger';
import Scroll from '@/components/scroll.vue';
import BoxAnimate from '@/components/boxAnimate.vue';

const props = defineProps<{
    num: number;
    ui: GameUi;
}>();

const frequentlyIcon: (AllIds | 'hero' | `X${number}`)[] = [
    'hero',
    'yellowKey',
    'blueKey',
    'redKey',
    'A492',
    'A494',
    'A497',
    'redPotion',
    'redGem',
    'blueGem',
    'I559',
    'X10194',
    'downPortal',
    'leftPortal',
    'upPortal',
    'rightPortal',
    'upFloor',
    'downFloor',
    'greenSlime',
    'yellowKnight',
    'bat',
    'slimelord'
];
const frequentlyColor: string[] = [
    '#ffffff',
    '#000000',
    '#ff0000',
    '#00ff00',
    '#0000ff',
    '#ffff00',
    '#00ffff',
    '#ff00ff',
    '#c0c0c0',
    '#808080',
    '#800000',
    '#800080',
    '#008000',
    '#808000',
    '#000080',
    '#008080'
];

let mainDiv: HTMLDivElement;

let danmaku = Danmaku.lastEditoredDanmaku ?? new Danmaku();

const cssOpened = ref(false);
const iconOpened = ref(false);
const fillOpened = ref(false);
const strokeOpened = ref(false);
const posting = ref(false);
const iconAll = ref(false);
const nowColor = ref('#ffffff');

const inputValue = ref(danmaku.text);
const cssInfo = ref(stringifyCSS(danmaku.style));
const cssError = ref('');

const map: Record<string, Ref<boolean>> = {
    css: cssOpened,
    icon: iconOpened,
    fillColor: fillOpened,
    strokeColor: strokeOpened
};

function openTool(tool: string) {
    iconAll.value = false;
    for (const [key, value] of Object.entries(map)) {
        if (key === tool) {
            value.value = !value.value;
        } else {
            value.value = false;
        }
    }
    if (tool === 'fillColor') {
        nowColor.value = danmaku.textColor;
    } else if (tool === 'strokeColor') {
        nowColor.value = danmaku.strokeColor;
    }
}

function send() {
    if (posting.value) return;
    if (danmaku.text === '') {
        tip('warning', '请填写弹幕！');
        return;
    }
    if (!core.isPlaying()) {
        tip('warning', '请进入游戏后再发送弹幕');
        return;
    }
    const { x, y } = core.status.hero.loc;
    const floor = core.status.floorId;
    if (isNil(x) || isNil(y) || isNil(floor)) {
        tip('warning', '当前无法发送弹幕');
        return;
    }

    danmaku.x = x;
    danmaku.y = y;
    danmaku.floor = floor;

    danmaku
        .post()
        .then(value => {
            if (value.data.code === 0) {
                danmaku.show();
                danmaku = new Danmaku();
                inputValue.value = '';
                cssInfo.value = '';
            }
        })
        .finally(() => {
            posting.value = false;
        });
}

function close() {
    mainDiv.classList.remove('danmaku-startup');
    mainDiv.classList.add('danmaku-close');
    sleep(400).then(() => {
        fixedUi.close(props.num);
    });
}

function input(value: string) {
    danmaku.text = value;
}

function inputEnter() {
    input(inputValue.value);
    inputCSS(cssInfo.value);
    send();
}

function inputCSS(text: string) {
    const { info, ret } = logger.catch(() => {
        return parseCss(text);
    });

    if (info.some(v => v.level > LogLevel.LOG)) {
        cssError.value = '语法错误';
        return;
    }

    const allow = Danmaku.checkCSSAllow(ret);
    if (allow.length > 0) {
        cssError.value = allow[0];
        return;
    } else {
        cssError.value = '';
    }

    danmaku.css(ret);
}

function inputColor(color: string) {
    nowColor.value = color;
    if (fillOpened.value) {
        danmaku.textColor = color;
    } else {
        danmaku.strokeColor = color;
    }
}

function addIcon(icon: AllIds | 'hero') {
    const iconText = `[i:${icon}]`;
    if (iconText.length + danmaku.text.length > 200) {
        tip('warn', '弹幕长度超限！');
        return;
    }
    danmaku.text += iconText;
    inputValue.value = danmaku.text;
}

function getAllIcons() {
    return [
        ...new Set(
            Object.values(core.maps.blocksInfo)
                .filter(v => v.cls !== 'tileset')
                .map(v => {
                    return v.id;
                })
        )
    ];
}

function clickOuter() {
    if (!iconAll.value) close();
    else iconAll.value = false;
}

let lockedBefore = false;
onMounted(() => {
    mainDiv = document.getElementById('danmaku-editor') as HTMLDivElement;
    mainDiv.classList.add('danmaku-startup');
    gameKey.disable();

    core.lockControl();
    mainDiv.addEventListener('focus', () => {
        lockedBefore = core.status.lockControl;
        core.lockControl();
        gameKey.disable();
    });
    mainDiv.addEventListener('blur', () => {
        gameKey.enable();
        if (!lockedBefore) core.unlockControl();
    });

    document.addEventListener('click', clickOuter);
});

onUnmounted(() => {
    if (danmaku.text !== '' || Object.keys(danmaku.style).length > 0) {
        Danmaku.lastEditoredDanmaku = danmaku;
    } else {
        delete Danmaku.lastEditoredDanmaku;
    }
    if (!lockedBefore) core.unlockControl();
    gameKey.enable();
    document.removeEventListener('click', clickOuter);
});
</script>

<style lang="less" scoped>
#danmaku-editor {
    position: fixed;
    width: 100%;
    bottom: 10px;
    display: flex;
    align-items: center;
    flex-direction: column-reverse;
    justify-content: end;
    font-size: 200%;
    background-color: #000b;
}

.danmaku-startup {
    animation: editor-startup 0.4s ease-out 0s 1 normal forwards running;
}

.danmaku-close {
    animation: editor-close 0.4s ease-in 0s 1 normal forwards running;
}

@keyframes editor-startup {
    0% {
        transform: translateY(70px);
    }
    100% {
        transform: none;
    }
}

@keyframes editor-close {
    0% {
        transform: none;
    }
    100% {
        transform: translateY(110px);
    }
}

#danmaku-input {
    height: 40px;
    width: 60%;
    display: flex;
    flex-direction: row;
    align-items: center;
    padding: 0 10px;
    margin-top: 10px;
}

#danmaku-input-div {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;

    #danmaku-input-input {
        width: 100%;
        height: 100%;
        font-size: 80%;
    }
}

.danmaku-tool {
    cursor: pointer;
    color: white;
    transition: color 0.2s linear;
    margin-right: 7px;
}

.danmaku-tool[open='true'],
.danmaku-tool:hover {
    color: aqua;
}

.danmaku-post {
    margin-left: 7px;
}

.danmaku-post[posting='true'] {
    color: gray;
    cursor: wait;
}

#danmaku-css {
    width: 60%;
    font-size: 60%;
    display: flex;
    flex-direction: row;
    align-items: center;
    white-space: nowrap;
    font-family: 'Fira Code';

    #danmaku-css-input {
        width: 100%;
        height: 100%;
        font-size: 80%;
        margin: 0 10px;
    }

    #danmaku-css-error {
        color: lightcoral;
    }
}

#danmaku-icon {
    width: 60%;
    display: flex;
    align-items: center;
    font-size: 80%;
    white-space: nowrap;
    justify-content: space-between;

    .danmaku-icon-scroll {
        width: calc(90% - 200px);
    }

    #danmaku-icon-div {
        display: flex;
        align-items: center;
        width: 100%;
    }

    .danmaku-icon-one {
        display: flex;
        align-items: center;
    }
}

#danmaku-icon-all-div {
    position: fixed;
    bottom: 110px;
    height: 50vh;
    background-color: #000b;
    border-radius: 20px;
    padding: 1%;
    font-size: 75%;
    width: 60%;
    display: flex;
    flex-direction: column;
    align-items: center;
    color: #dddd;

    #danmaku-all-container {
        display: flex;
        flex-direction: row;
        flex-wrap: wrap;
        align-items: center;
    }

    .danmaku-all-scroll {
        height: calc(100% - 70px);
    }
}

#danmaku-color {
    width: 60%;
    display: flex;
    align-items: center;
    white-space: nowrap;
    justify-content: space-between;
    font-family: 'Fira Code';
    font-size: 75%;

    #danmaku-color-container {
        display: flex;
        align-items: center;
        margin: 10px;
        width: 100%;
    }

    .danmaku-color-one {
        width: 30px;
        min-width: 30px;
        height: 20px;
        border-radius: 6px;
        margin-right: 7px;
        border: 2px solid transparent;
        transition: border 0.1s linear;
    }

    .danmaku-color-one[selected='true'],
    .danmaku-color-one:hover {
        border: 2px solid gold;
    }

    .danmaku-color-scroll {
        width: calc(100% - 400px);
    }

    #danmaku-color-input {
        width: 200px;
    }
}

.danmaku-enter-active,
.danmaku-leave-active {
    transition: all 0.4s ease-out;
    position: absolute;
    bottom: 50px;
}

.danmaku-enter-from,
.danmaku-leave-to {
    opacity: 0;
    transform: translateY(50px);
}

.danmaku-icon-enter-active,
.danmaku-icon-leave-active {
    transition: all 0.3s ease-out;
}

.danmaku-icon-enter-from,
.danmaku-icon-leave-to {
    opacity: 0;
    transform: translateY(50px);
}

@media screen and (max-width: 600px) {
    #danmaku-input {
        width: 90%;
    }

    #danmaku-css {
        width: 90%;
    }

    #danmaku-icon {
        width: 90%;
    }
}
</style>
