import { defineComponent, onMounted , ref, effect} from "vue";
import { string } from "vue-types";
import { useCompData } from ".";
import { useEditor } from "../../../..";
import { View } from "../View";
import { CompUI } from "../..";
import { values } from "lodash";
import { Angle, VectorLenth } from "@/modules/editor/controllers/SelectCtrl/objects/mathUtils";
import { CompObject } from "@/modules/editor/controllers/SelectCtrl/compObj";
import { ObjsContainer } from "@/modules/editor/controllers/SelectCtrl/ObjsContainer";

function findNearestPoint(points: number[][], w:number, h:number, sx:number, sy:number) {
   const n = points.length;
   let minv = 100000;
    let minIndex = -1;
    const positions = []

   for(let i=0; i<n; i++) {
      const p = points[i];
      const x = w *p[0];
      const y = h *p[1];
      positions.push([x, y]);

      const ln = (sx-x)*(sx-x) + (sy-y)*(sy-y);
      if ( ln < minv ) {
        minIndex = i;
        minv = ln;
         if(!(sx < (x -10) || sx > (x + 10) || sy < (y -10) || sy > (y+10) ) ) {
            return {clicked: true, index: i};
         }
      }
   }   

   let preIndex = minIndex -1;
   if (preIndex < 0 ) preIndex = n-1;
   let afterIndex = minIndex + 1;
   if ( afterIndex >= n) afterIndex = 0;

   const currV = {x:sx-positions[minIndex][0], y:sy-positions[minIndex][1]};
   const preV = {x:positions[preIndex][0]-positions[minIndex][0], y:positions[preIndex][1]-positions[minIndex][1]}
   const afterV = {x:positions[afterIndex][0]-positions[minIndex][0], y:positions[afterIndex][1]-positions[minIndex][1]}

  const a1 =  Angle(currV, preV)
  const a2 =  Angle(currV, afterV);

  if (a1 < a2) {
    return {index: preIndex};
  }

  return {index: minIndex};
}

function normalize(v1:{x:number,y:number}) {
    let x = v1.x;
    let y = v1.y;
    const s = Math.sqrt(x*x + y*y);
    v1.x = x / s;
    v1.y = y / s;
    return v1;
}

type PointItem = {
    x: number;
    y: number;
    cx: number;
    cy: number;

    preLineX: number; //界面显示控制点
    preLineY: number; //界面显示控制点
    aftLineX: number; //界面显示控制点
    aftLineY: number; //界面显示控制点

    preCirleX: number; //界面显示控制点
    preCirleY: number; //界面显示控制点

    aftCirleX: number; //界面显示控制点
    aftCirleY: number; //界面显示控制点

    isLine: boolean;
}

function parsePoints( points:number[][],  width:number, height:number) {
    let out :PointItem[] = [];
    let n = points.length;
    for(let i=0; i<n; i++) {
        const p = points[i]

        const x = p[0]*width, y = p[1]*height;

          //绘制控制点的位置
          const cx = width * p[2];
          const cy = height *p[3];

          let v = {x: cx - x, y: cy-y};
          v = normalize(v);

          let slen = 90;
          const preCirleX = x -v.x * slen, preCirleY = y-v.y *slen;
          const aftCirleX = x +v.x *slen,  aftCirleY = y+v.y*slen;
          
          slen = 80;

          const preLineX = x -v.x * slen, preLineY = y-v.y *slen;
          const aftLineX = x +v.x *slen,  aftLineY = y+v.y*slen;


        out.push({x, y, cx, cy, isLine: p[4] != undefined, 
                preCirleX,preCirleY, aftCirleX, aftCirleY,
                preLineX, preLineY, aftLineX, aftLineY});

    }
    return out;
}


function clickTest(points:PointItem[], e:MouseEvent, pxToDesignSize:any,) {
    const x = pxToDesignSize(e.offsetX )
    const y = pxToDesignSize(e.offsetY)
    let n = points.length;
    let pIndex = -1;
    let clickCurve = false;
    let clickLine = false;
    let moving = false;

    while(n--) {
        const p = points[n];
        let px = p.x;
        let py = p.y;

        const rect = 20

        if(!(x < (px -rect) || x > (px + rect) || y < (py -rect) || y > (py+rect) ) ) {
            pIndex = n;
            break;
        }


        if(!(x < (p.aftCirleX -rect) || x > (p.aftCirleX + rect) || y < (p.aftCirleY -rect) || y > (p.aftCirleY+rect) ) ) {
            pIndex = n;
            clickCurve = true;
            break;
        }

        if(!(x < (p.preLineX -rect) || x > (p.preLineX + rect) || y < (p.preLineY -rect) || y > (p.preLineY+rect) ) ) {
            pIndex = n;
            clickLine = true;
            break;
        }
    }
    if (pIndex == -1) {
          //ming
          const dta = 5
          if(!(x < (20 - dta) || x > (20 + dta) || y < (20 -dta) || y > (20 + dta) ) ) {
              moving = true;
          }
    }
    return {clickLine, clickCurve, pIndex, moving, x, y};
}

export const Component = defineComponent({
  props: {
    compId: string().isRequired,
  },
  setup(props) {
    const { helper, controls , store} = useEditor();
    const data = useCompData(props.compId);
    const canvasRef =  ref<HTMLCanvasElement>();
    onMounted(()=>{
        
        canvasRef.value?.addEventListener("dblclick", function(e:MouseEvent){
            
            const x = helper.pxToDesignSize(e.offsetX )
            const y = helper.pxToDesignSize(e.offsetY)
            
            const points = data.value.points as number[][];
            const w = data.layout.size[0];
            const h = data.layout.size[1];
            //判断直线相交求解点到直线的距离
            const ret = findNearestPoint(data.value.points, w , h, x, y);
            //判断是否
            console.log("dbclick=>xxxxx", ret);
            if (ret.clicked) {//点击删除
                points.splice(ret.index, 1);
                if (points.length < 2) {
                    return;
                }

            } else {
                let next = ret.index + 1;
                if (next >= points.length ) {
                    next = 0;
                }
                //计算
                const x1 = x / w, y1= y / h;
                points.splice(ret.index+1, 0, [x1, y1 ,  (x1 + points[next][0])/ 2.0 , (y1 + points[next][1]) / 2.0 ]);
            }

            draw();
        })

        canvasRef.value?.addEventListener("mousedown", function(e:MouseEvent){
                if (store.currCompId != props.compId) return;

                const el = canvasRef.value as HTMLCanvasElement;
                const width = data.layout.size[0];
                const height = data.layout.size[1];
                const ps = parsePoints(data.value.points as number[][], width, height)
                const ret = clickTest(ps, e, helper.pxToDesignSize);
                if (ret.pIndex == -1 && !ret.moving) return;

                const dragingX = ret.x;
                const dragingY = ret.y;

                const points = data.value.points as number[][];
                const initValues = ret.pIndex != -1 ? points[ret.pIndex].slice(0) : {} as any;
                const initPoint = ret.pIndex != -1 ? {...ps[ret.pIndex]} : {} as any;
                const initPoints = points.map(item=>item.slice(0));

                e.preventDefault();
                e.stopPropagation();
                
                const isDragingIndex = ret.pIndex;

                const box = controls.selectCtrl.getCurrCardViewPortBox();

                const mvingPoint = !ret.clickCurve && !ret.clickLine
                let initControlpLen :number | undefined = undefined;

                const move =  function (e:MouseEvent){
                    e.preventDefault();
                    e.stopPropagation();

                    const obj = controls.selectCtrl.objContainer as ObjsContainer;  
                    const cardX = e.clientX - box.left, cardY =  e.clientY - box.top;
                    const p = {x: cardX, y:cardY} as any;
                    obj.parent.worldTransform.applyInverse(p, p);
                    obj.parent.updateTransform();

                    const x = helper.pxToDesignSize(p.x), y =  helper.pxToDesignSize(p.y);
                    const offx = ( x - dragingX) / width;
                    const offy = ( y -  dragingY) / height;
                    
                    if (ret.moving) {//移动所有
                        points.forEach((p,i)=>{
                            p[0] = initPoints[i][0] + offx;
                            p[1] = initPoints[i][1] + offy;
                            p[2] = initPoints[i][2] + offx;
                            p[3] = initPoints[i][3] + offy;
                        })
                        draw();
                        return;
                    }

                    if (mvingPoint) {
                        points[isDragingIndex][0] = initValues[0] + offx;
                        points[isDragingIndex][1] = initValues[1] + offy;
    
                        points[isDragingIndex][2] = initValues[2] + offx;
                        points[isDragingIndex][3] = initValues[3] + offy;

                    } else if (ret.clickCurve) {//移动曲线
                        if (initControlpLen == undefined) { //初始控制点的长度
                            initControlpLen = VectorLenth( initPoint.cx - initPoint.x, initPoint.cy - initPoint.y);
                        }

                        const half = initControlpLen / 2.0;

                        //当前鼠标到远点的长度
                        const len = half + VectorLenth( x - initPoint.x, y - initPoint.y) / 90.0 * half;

                        let v = normalize({x: x - initPoint.x, y: y - initPoint.y});
                        if (e.shiftKey) {//一条直线
                            let nextIndex = ret.pIndex + 1;
                            if (nextIndex >= ps.length) {
                                nextIndex = 0;
                            }
                            v = normalize({x: ps[nextIndex].x - initPoint.x, y: ps[nextIndex].y - initPoint.y});
                        }

                        points[isDragingIndex][2] = (initPoint.x + v.x * len) / width;
                        points[isDragingIndex][3] = (initPoint.y + v.y * len) / height;
                    }
                    draw();
                }

                if  ( !ret.clickCurve && !ret.clickLine && !ret.moving) {
                    el.addEventListener("mouseleave", function(){
                        document.removeEventListener("mousemove", move);
                    }, {once: true})
                }

                document.addEventListener("mousemove", move)

                document.addEventListener("mouseup", function(e:MouseEvent){
                    document.removeEventListener("mousemove", move);
                }, {once: true});

        }, )

        effect(draw);
    })

    

   
    function draw() {
        const canvas = canvasRef.value as HTMLCanvasElement;
        if (!canvas) return;

        const ctx = canvasRef.value?.getContext("2d") as CanvasRenderingContext2D;

        const width = data.layout.size[0];
        const height = data.layout.size[1];
        canvas.width = Math.ceil(Math.max(1, width));
        canvas.height = Math.ceil(Math.max(1, height));
        ctx.clearRect(0, 0, canvas.width, canvas.height);
        ctx.lineWidth = data.value.lineWidth;

        if (data.value.reverseFill) {
            ctx.fillStyle = data.value.fillColor;
            ctx.fillRect(0, 0, canvas.width, canvas.height);
        }
        ctx.setLineDash([]);
        ctx.strokeStyle = data.value.lineColor;
    
        const padding = 0.2;

        ctx.lineJoin = "round";
        ctx.beginPath();
       

        let points = data.value.points as number[][];
        if (data.value.points.length == 0) {
            data.value.points = [[padding, 0.5, 0.4, 0.1], [1 - padding, 0.5, 0.5, 0.85]];
            points = data.value.points;
        }

        const ps = parsePoints(data.value.points, width, height);
        
        ctx.save();

        ps.forEach((p, index)=>{
            const x = p.x
            const y = p.y
            if (index == 0) {
                ctx.moveTo(x, y)
            } else {
                const preIndex = index -1;
                const prep = ps[preIndex];
                if (!prep.isLine) {
                    ctx.quadraticCurveTo( prep.cx, prep.cy,  x, y);
                } else {
                    ctx.lineTo(x, y);
                }
            }
        })

        if (data.value.isClose) {
            const prep = ps[points.length-1];
            const lastPoint =   ps[0];
            if (!prep.isLine) {
                ctx.quadraticCurveTo( prep.cx, prep.cy,  lastPoint.x, lastPoint.y);
            } 
            ctx.closePath();
        }

        if (data.value.lineWidth !== 0) {
            ctx.stroke();
        }

        if (data.value.isFill)    {
            let bColor = data.value.fillColor;
            if (!bColor) bColor = data.value.lineColor;
            ctx.fillStyle = bColor;
            if (data.value.reverseFill) {
                ctx.fillStyle = "red";
                // 设置剪切区域
                ctx.clip();
                // 将当前路径指定的区域颜色扣除
                ctx.globalCompositeOperation = "destination-out";
            }
            ctx.fill();
        }
        ctx.restore();

        //绘制辅助gizmo
        if (store.isEditMode  && store.currCompId == props.compId) {

            ctx.lineWidth = 2;
            ctx.strokeStyle = "orange";
            ctx.setLineDash([10, 5])

            ps.forEach((p, index)=>{   
                if (index == 0) {
                    ctx.beginPath();
                    ctx.moveTo(p.x, p.y);
                } else {
                    ctx.lineTo(p.x, p.y);
                }
            });

            if (data.value.isClose && ps.length > 2) {
                ctx.lineTo(ps[0].x, ps[0].y);
            }

            ctx.stroke();
            ctx.setLineDash([])

            ps.forEach((p)=>{
                const x = p.x
                const y = p.y
            
                ctx.fillStyle = "red"
                ctx.beginPath();
                ctx.arc(x, y, 5,  0, Math.PI*2);
                ctx.fill();

              
                ctx.beginPath()
                // ctx.setLineDash([5,5])
                ctx.moveTo(p.preLineX, p.preLineY);
                ctx.lineTo(p.aftLineX, p.aftLineY);
                ctx.stroke();

                // ctx.beginPath()
                // ctx.arc(p.preCirleX, p.preCirleY, r, 0, Math.PI*2)
                // ctx.stroke();
                
                const r = 10
                ctx.beginPath()
                ctx.arc(p.aftCirleX, p.aftCirleY, r, 0, Math.PI*2)
                ctx.fill();
            })
            ctx.beginPath()
            ctx.arc(20, 20 , 5, 0, Math.PI*2)
            ctx.fill();
        }
    }

    return () => (
      <View compId={props.compId}>
         <canvas ref={canvasRef} style={{width:"100%", height: "100%"}}> </canvas>
      </View>
    );
  },
});
