import { Html } from '@react-three/drei'
import { useEffect, useRef, useState } from 'react';
import * as THREE from 'three';
import { useFrame, useThree } from '@react-three/fiber';
import gsap from 'gsap';
import { SplitText } from 'gsap/SplitText';

gsap.registerPlugin(SplitText) ;


export const PointScale=200;
const PointSize=1;

const PointDuration=5;
const KeywordOffset=0;
const SceneDuration=0.5; // 總場景時間，用於計算延遲

const DEPTH_CONFIG = {
    NEAR: 1200,    // 在此距離內顯示最清晰
    FAR: 1500,    // 超過此距離後幾乎隱藏或變成符號
    FADE_START: 800
};



export const PointContentType={
    Full: 'full',
    Teaser: 'teaser',
    Blur: 'blur',
    Symbol: 'symbol',
}


export default function Point({point, index, totalPoints, result, showContent, showKeyword, contentType, textToShow, color, useAnimation}) {

    const [payload, setPayload]=useState();
    const [showPayload, setShowPayload]=useState(false);
    
    const meshRef=useRef();
    const refText=useRef();
    const { camera } = useThree();
    const refAnimation=useRef({t:0});

    function getRandomText(text){

        if(contentType==PointContentType.Blur) return text.slice(0, textToShow) + '...';

        const length=text.length;
        const characters='*@#$%^&';
        let result='';
        for(let i=0; i<length; i++){
            if(Math.random() < 0.8)
                result+=characters.charAt(Math.floor(Math.random() * characters.length));
            else
                result+=' ';
        }
        return result.slice(0, textToShow/2);
    }

    function getContent(){
        if(!payload) return '';
        // console.log("Point contentType:", contentType, payload);
        // if(payload.normalized_time===-1){
        //     return <span>{payload.text}</span>
        // }

        switch(contentType){
            case PointContentType.Full:
                return payload.content.slice(0, textToShow) + (payload.content.length > textToShow ? '...' : '');
            case PointContentType.Teaser:
                return `<span>${payload.teaser}</span>`;
            case PointContentType.Blur:
            case PointContentType.Symbol:
                const start=payload.content.indexOf(payload.teaser);
                if(start===-1) 
                    return `<span>${payload.teaser}</span>`;

                const before=payload.content.substring(0, start);
                const after=payload.content.substring(start + payload.teaser.length);   

                return `<span class=${contentType}>${getRandomText(before)}</span>${payload.teaser}<span class=${contentType}>${getRandomText(after)}</span>`;
        }

    }

    // 每幀計算距離並更新樣式，同時處理縮放動畫
    useFrame((state) => {
        if (!meshRef.current || !refText.current || !payload) return;

        
         

        // const time = state.clock.elapsedTime;
        // const lifeTimeOffset = (payload.number / payload.total) || 0;

        // 1. 處理物體本身的脈衝縮放動畫 (替代 GSAP)
        // 使用正弦波模擬 PointDuration 的循環
        const pulseSpeed = Math.PI / PointDuration;
        const pulse = 1;//Math.abs(Math.sin(time * pulseSpeed + lifeTimeOffset * Math.PI));
        const currentMeshScale = useAnimation? THREE.MathUtils.lerp(0.5, PointSize, pulse): PointSize;
        meshRef.current.scale.set(currentMeshScale, currentMeshScale, currentMeshScale);

        // 2. 計算與攝影機的距離處理深度視覺效果
        const worldPosition = new THREE.Vector3();
        meshRef.current.getWorldPosition(worldPosition);
        const distance = camera.position.distanceTo(worldPosition);

        // 根據距離計算 alpha (0 到 1)
        let alpha = 1 - (distance - DEPTH_CONFIG.NEAR) / (DEPTH_CONFIG.FAR - DEPTH_CONFIG.NEAR);
        alpha = THREE.MathUtils.clamp(alpha, 0.2, 1);
       
        // 根據距離調整縮放感 (非線性縮放讓遠處文字縮小)
        const depthScaleFactor = THREE.MathUtils.clamp(1.5 - (distance / 300), 0.5, 1.2);

        // 更新 HTML 樣式
        if (refText.current) {

                           
            // 結合深度縮放與物體本身的脈衝狀態
            const finalHtmlScale = depthScaleFactor * (currentMeshScale / PointSize);
            refText.current.style.transform = `translate(-50%, -50%) scale(${finalHtmlScale})`;
            
            if(payload.keywords.length==1){
            // meshRef.current.scale.set(PointSize, PointSize, PointSize);
                refText.current.style.opacity = 1;
                refText.current.style.transform = `translate(-50%, -50%) scale(1)`;
                refText.current.style.filter = `none`;
             
            }else{    
                 refText.current.style.opacity *= alpha;
                // 加入 CSS 濾鏡：越遠越模糊
                const blurAmount = distance > DEPTH_CONFIG.FADE_START ? (distance - DEPTH_CONFIG.FADE_START) / 20 : 0;
                refText.current.style.filter = `blur(${Math.min(blurAmount, 2)}px)`;
            }
            // 效能優化
            // refText.current.style.display = alpha <= 0.01 ? 'none' : 'block';
        }
    });
    function setTextStyle(t){
        if(refText.current){
            refText.current.style.opacity=t;
            refText.current.style.transform=`translate(-50%, -50%) scale(${t})`;
        }
    }

    useEffect(()=>{
        // return;

        if(!payload) return;
        
        const lifeTime=payload.normalized_time;
        if(lifeTime===-1) return; // keyword 不參與動畫
        // if(!useAnimation) {
        //     setTextStyle(1);
        //     return;
        // }

        // console.log("Point lifeTime:", lifeTime);

        // animate point size based on lifeTime
        const targetSize=1;

        const timeline=gsap.timeline({ repeat:-1});
        timeline.fromTo(refAnimation.current,{t:0}, {
            t:0,
            onUpdate: ()=>{
                setTextStyle(refAnimation.current.t);
            }
        }, lifeTime * SceneDuration);
        timeline.to(refAnimation.current,{
            t: 1,
            duration: PointDuration,
            ease: 'power1.inOut',
            onComplete: ()=>{
                // console.log("Show text for point:", index);
            },
            onUpdate: ()=>{
                setTextStyle(refAnimation.current.t);
            }
        }); // 根據 lifeTime 設定延遲時間

      

        timeline.to(refAnimation.current,{
            t: 0,
            duration: PointDuration,
            onComplete: ()=>{
                // console.log("Hide text for point:", index);
            },
            onUpdate: ()=>{
                 setTextStyle(refAnimation.current.t);
            }
        }); 
        // timeline.to(refAnimation.current,{t:0}, {
        //     duration: SceneDuration - (lifeTime * SceneDuration + PointDuration * 2),
        // }); // 剩餘時間保持隱藏

        timeline.play();

        return ()=>{
            timeline.kill();
        };

    },[payload]);

    useEffect(()=>{
        
        if(!showContent) return;
        if(!refText.current) return;

        // const tosplit=refText.current.getElementsByClassName('splittext')[0];
        // if(!tosplit) return;

        // let split=SplitText.create(tosplit, {type: "words, chars"});
        // console.log("SplitText chars:", split.chars.length);

        // gsap.fromTo(split.chars, {
        //     // opacity: 0,
        //     y: 50,
        //     stagger: 0.05
        // }, {
        //     // opacity: 1,
        //     y: -50,
        //     duration: 0.5,
        //     ease: 'power2.inOut',
        //     repeat:-1,
        // });

        // return ()=>{
        //     // split.revert();
        //     gsap.killTweensOf(split.chars);
        // };
    },[showContent])

    useEffect(()=>{
        
        if(!result) return;

        // console.log("Point result:", result, color);
        if(result?.type==='keyword'){
            const title=JSON.parse(result.payload.text??'{}').title;
            const payloadKeyword={
                ...JSON.parse(result.payload.text??'{}'),
                keywords: [title],
                number: 0,
                total: 1,
                content: title || '',
                teaser: title ||'',
                normalized_time: -1,
                type: result.type || 'keyword',
            };
            setPayload(payloadKeyword);
            return;
        }
        setPayload({
            ...JSON.parse(result.payload.metadata??'{}'),
            keywords: result.payload.keywords || [],
            number: result.payload.number || 0,
            total: result.payload.total || 1,
            content: JSON.parse(result.payload.metadata??'{}').text || '',
            teaser: result.payload.teaser || '',
            normalized_time: result.payload.normalized_time || 0,
            type: result.type || 'data',
        });

    },[result]);


    return (
        <mesh ref={meshRef} position={[point[0]*PointScale, point[1]*PointScale, point[2]*PointScale]}>
            <sphereGeometry args={[PointSize, 32, 32]} />
            <meshStandardMaterial 
                color={new THREE.Color().set(color)} 
                emissive={new THREE.Color().set(color)}
                emissiveIntensity={0.5}
            />
            <Html>
                <div ref={refText} className=' p-2 select-none text-center opacity-0 flex flex-col items-center justify-center'>
                    {showKeyword && payload?.keywords.length>1 && <div className={`flex flex-row justify-center flex-wrap text-[1rem] ${showKeyword ? 'block' : 'hidden'}`}
                        style={{color: color || 'white'}}>
                        {payload?.keywords.map((el, index)=><span key={index} className='px-2  bg-gray-800 rounded-full' style={{transform: `translate(${Math.random() * KeywordOffset}px,${Math.random() * KeywordOffset}px)`}}>{el}</span>)}
                    </div>}
                    {/* {color!='white' && !showKeyword && payload?.keywords.length>1 && <div className='w-[1rem] aspect-square rounded-full' style={{backgroundColor: color}}></div>} */}
                    {<div
                        className={`text-[2rem] rounded p-2 text-center max-w-[50vw] min-w-[20vw] splittext ${showContent ? 'block' : 'hidden'} ${payload?.type??''}`}
                        // style={{width: `${Math.random()*(payload?.content.length/5 || 10) + 20}vw`}}
                        style={{color: color}}
                        dangerouslySetInnerHTML={{__html: getContent()}}
                    ></div>}
                </div>
            </Html>
        </mesh>
    )
}