<template>
    <view class="out">
        <view v-if="loading" class="loading">
            <view class="semicircle-loader"></view>
        </view>
        <view v-else class="container" id="pixi-box" ref="pixiContainerRef"></view>
    </view>
</template>

<script setup>
import { onMounted, onUnmounted, ref, nextTick, watch } from 'vue';

const props = defineProps({
    tags: {
        type: Array,
        default: [],
    },
    loading: {
        type: Boolean,
        default: false,
    },
});
const emit = defineEmits(['tag-click']);

// DOM Ref
const pixiContainerRef = ref(null);

// PIXI 变量
let app = null;
let tagsContainer = null;
let activeTagInstances = [];

// 配置数据
const tagsConfig = ref([
    { bgColor: 0x0069fe, fontColor: 0xffffff, size: 16, opacity: 1.0, angle: 0, radius: 0 },
    {
        bgColor: 0x87e2ec,
        fontColor: 0xffffff,
        size: 14,
        opacity: 1,
        angle: -Math.PI / 2,
        radius: 68,
        tailRotation: Math.PI / 2,
    },
    {
        bgColor: 0xffebeb,
        tailColor: 0xffe1e1,
        fontColor: 0xff6969,
        size: 11.5,
        opacity: 1,
        angle: -Math.PI / 4.2,
        radius: 125,
        tailRotation: (3 * Math.PI) / 4.5,
    },
    {
        bgColor: 0x21ea85,
        fontColor: 0xffffff,
        size: 15,
        opacity: 1,
        angle: -Math.PI / 10,
        radius: 130,
        tailRotation: (3 * Math.PI) / 4.2,
    },
    {
        bgColor: 0xebf3ff,
        tailColor: 0xb9d3ff,
        fontColor: 0x1d71ef,
        size: 12,
        opacity: 1,
        angle: Math.PI / 18,
        radius: 135,
        tailRotation: (3 * Math.PI) / 4.3,
    },
    {
        bgColor: 0xffd4b6,
        fontColor: 0xffffff,
        size: 14,
        opacity: 1,
        angle: Math.PI / 4.3,
        radius: 100,
        tailRotation: -(3 * Math.PI) / 4.5,
    },

    {
        bgColor: 0xff9400,
        fontColor: 0xffffff,
        size: 14,
        opacity: 1,
        angle: (2 * Math.PI) / 3,
        radius: 92,
        tailRotation: -Math.PI / 2.4,
    },
    {
        bgColor: 0xebf3ff,
        tailColor: 0xb9d3ff,
        fontColor: 0x1d71ef,
        size: 10.5,
        opacity: 1,
        angle: (5.4 * Math.PI) / 6,
        radius: 110,
        tailRotation: (3 * Math.PI) / 1.79,
    },
    {
        bgColor: 0xff6969,
        fontColor: 0xffffff,
        size: 14,
        opacity: 1,
        angle: (6.3 * Math.PI) / 5.8,
        radius: 120,
        tailRotation: Math.PI / 2.9,
    },
    {
        bgColor: 0xfce9c9,
        fontColor: 0xfbc55f,
        size: 13,
        opacity: 1,
        angle: (7.2 * Math.PI) / 5.9,
        radius: 120,
        tailRotation: Math.PI / 3,
    },
]);

watch(
    () => props.tags,
    (val) => {
        if (val && val.length) {
            tagsConfig.value.map((tag, index) => {
                // console.log(val[index])
                tag.name = val[index]?.job_name;
            });
            setTimeout(() => {
                initPixi();
            }, 100);
        }
    },
    { deep: true }
);

onMounted(async () => {
    window.addEventListener('resize', handleResize);
});

onUnmounted(() => {
    window.removeEventListener('resize', handleResize);
    if (app) {
        app.destroy(true, { children: true, texture: true, baseTexture: true });
        app = null;
    }
});

const getContainerDOM = () => {
    const refVal = pixiContainerRef.value;
    if (!refVal) return document.getElementById('pixi-box');
    if (refVal.$el) return refVal.$el;
    return refVal;
};

const clamp = (num, min, max) => Math.min(Math.max(num, min), max);

const initPixi = () => {
    const container = getContainerDOM();
    if (!container) return;

    const width = container.clientWidth || 300;
    const height = container.clientHeight || 300;

    if (app) return;

    app = new PIXI.Application({
        width: width,
        height: height,
        backgroundAlpha: 0,
        backgroundColor: 0xf5f7fa,
        antialias: true,
        resolution: window.devicePixelRatio || 1,
        autoDensity: true,
    });
    app.view.style.touchAction = 'auto';

    container.appendChild(app.view);

    tagsContainer = new PIXI.Container();
    app.stage.addChild(tagsContainer);

    renderScene(width, height);
};

const renderScene = (sw, sh) => {
    let ratio = window.innerWidth / 400;
    if (ratio < 1) ratio = 1;
    tagsContainer.removeChildren();
    activeTagInstances = [];

    tagsConfig.value.forEach((data, index) => {
        const scaledRadius = data.radius * ratio;

        let x = sw / 2 + scaledRadius * Math.cos(data.angle);
        let y = sh / 2 + scaledRadius * Math.sin(data.angle);

        const tag = createTag(data, index, ratio);

        tagsContainer.addChild(tag);

        const safeW = tag.width / 2 + 10;
        const safeH = tag.height / 2 + 10;

        // 强制修正 x 和 y，使其不超出屏幕
        x = clamp(x, safeW, sw - safeW);
        y = clamp(y, safeH, sh - safeH);

        tag.x = x;
        tag.y = y;

        // 4. 保存元数据
        tag.userData = {
            originalX: x,
            originalY: y,
            angle: data.angle,
            radius: scaledRadius,
            floatOffset: Math.random() * Math.PI * 2,
            floatSpeed: 0.01 + Math.random() * 0.02,
            floatRange: 2 + Math.random() * 2,
            safeH: safeH,
        };

        if (data.radius > 0) {
            const tail = createCometTail(
                data.tailColor || data.bgColor,
                data.tailRotation,
                tag.width,
                tag.height,
                ratio
            );
            tag.addChildAt(tail, 0);
            tag.updateTail = () => tail.updateAnim();
        }

        activeTagInstances.push(tag);
    });

    // 动画循环
    app.ticker.add(() => {
        const screenH = app.screen.height;
        activeTagInstances.forEach((tag) => {
            const meta = tag.userData;
            if (meta) {
                // 计算新的浮动位置
                meta.floatOffset += meta.floatSpeed;
                let nextY = meta.originalY + Math.sin(meta.floatOffset) * meta.floatRange;

                // 再次进行边界检查
                if (nextY < meta.safeH) nextY = meta.safeH;
                if (nextY > screenH - meta.safeH) nextY = screenH - meta.safeH;

                tag.y = nextY;

                if (tag.updateTail) tag.updateTail();
            }
        });
    });
};

const createTag = (tagData, index, ratio) => {
    if (ratio > 1) ratio = ratio * 0.9;
    const tagGroup = new PIXI.Container();
    tagGroup.eventMode = 'static';
    tagGroup.cursor = 'pointer';

    tagGroup.on('pointertap', () => emit('tag-click', tagData));

    const text = new PIXI.Text(tagData.name, {
        fontFamily: ['PingFang SC', 'Microsoft YaHei', 'Arial'],
        fontSize: tagData.size * ratio,
        fill: tagData.fontColor,
        padding: 4 * ratio,
        resolution: 2,
    });
    text.anchor.set(0.5);

    const paddingH = 26 * ratio;
    const paddingV = 10 * ratio;
    let bgWidth = text.width + paddingH;
    let bgHeight = text.height + paddingV;

    if (index === 0) bgWidth = Math.max(bgWidth, tagData.size * 4.5);

    const bg = new PIXI.Graphics();
    bg.beginFill(tagData.bgColor, tagData.opacity ?? 1);
    bg.drawRoundedRect(-bgWidth / 2, -bgHeight / 2, bgWidth, bgHeight, bgHeight / 2);
    bg.endFill();

    tagGroup.addChild(bg);
    tagGroup.addChild(text);

    return tagGroup;
};

const createCometTail = (bgColor, tailRotation, parentWidth, parentHeight, ratio) => {
    if (ratio > 1) ratio = ratio;
    const tailGroup = new PIXI.Container();
    const graphics = new PIXI.Graphics();
    tailGroup.addChild(graphics);

    const baseLength = 45 * ratio;
    const startWidth = parentHeight + 20 * ratio;
    const endWidth = parentHeight * 0.4;

    let breathPhase = Math.random() * Math.PI * 2;
    const breathSpeed = 0.04;

    tailGroup.updateAnim = () => {
        breathPhase += breathSpeed;
        const breathScale = 0.85 + 0.15 * Math.sin(breathPhase);
        graphics.clear();
        const currentLength = baseLength * breathScale;

        const cos = Math.cos(tailRotation);
        const sin = Math.sin(tailRotation);
        const perpX = -sin;
        const perpY = cos;

        const p1 = { x: perpX * (startWidth / 2), y: perpY * (startWidth / 2) };
        const p2 = { x: -perpX * (startWidth / 2), y: -perpY * (startWidth / 2) };
        const endCX = cos * currentLength;
        const endCY = sin * currentLength;
        const p3 = { x: endCX - perpX * (endWidth / 2), y: endCY - perpY * (endWidth / 2) };
        const p4 = { x: endCX + perpX * (endWidth / 2), y: endCY + perpY * (endWidth / 2) };

        const segments = 8;
        for (let i = 0; i < segments; i++) {
            const t1 = i / segments;
            const t2 = (i + 1) / segments;
            const alpha = 0.4 * (1 - t1);
            const sp1 = { x: p1.x + (p4.x - p1.x) * t1, y: p1.y + (p4.y - p1.y) * t1 };
            const sp2 = { x: p2.x + (p3.x - p2.x) * t1, y: p2.y + (p3.y - p2.y) * t1 };
            const ep1 = { x: p1.x + (p4.x - p1.x) * t2, y: p1.y + (p4.y - p1.y) * t2 };
            const ep2 = { x: p2.x + (p3.x - p2.x) * t2, y: p2.y + (p3.y - p2.y) * t2 };
            graphics.beginFill(bgColor, alpha);
            graphics.moveTo(sp1.x, sp1.y);
            graphics.lineTo(sp2.x, sp2.y);
            graphics.lineTo(ep2.x, ep2.y);
            graphics.lineTo(ep1.x, ep1.y);
            graphics.endFill();
        }
    };
    tailGroup.updateAnim();
    return tailGroup;
};

const handleResize = () => {
    const container = getContainerDOM();
    if (!app || !container) return;
    app.destroy(true, { children: true, texture: true, baseTexture: true });
    app = null;
    initPixi();
};
</script>

<style scoped>
.out {
    width: 100%;
    height: 100%;
}
.loading {
    width: 100%;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
}
.semicircle-loader {
    width: 150rpx;
    height: 150rpx;
    border: 12rpx solid #f3f3f3;
    border-top: 12rpx solid #3498db;
    border-radius: 50%;
    animation: spin 1.2s linear infinite;
}

@keyframes spin {
    0% {
        transform: rotate(0deg);
    }
    100% {
        transform: rotate(360deg);
    }
}
.container {
    width: 100%;
    height: 100%;
    position: relative;
    overflow: hidden;
    color: #b9d3ff;
}
</style>
