<template>
    <el-upload
        v-model:file-list="fileList"
        class="upload-demo"
        :on-change="handleChange"
        action=""
        multiple
        :limit="3"
        :on-exceed="handleExceed"
        :auto-upload="false"
        v-if="!board"
    >
        <el-button type="primary">Click to upload</el-button>
    </el-upload>
    <div style="background-color: #eee; position:relative; overflow:hidden;" :style="{width:board?.document.width+'px',height:board?.document.height+'px'}" id="ImageContainer"></div>

</template>
<script setup lang="ts">
import { reactive, ref } from "vue";
import type { UploadProps, UploadUserFile } from 'element-plus'
import { ElMessage, ElMessageBox } from 'element-plus'
import PSD from 'psd.js'

const zIndex = ref<number>(1000)
const fileList = ref<UploadUserFile[]>([])
const board = ref<any>(null)
const prevLayer = ref<any>()
const Ornts:any = {
  'Hrzn':'horizontal-tb',
}

const handleChange: UploadProps['onChange'] = (uploadFile, uploadFiles) => {
    if(uploadFile){
        var url = URL.createObjectURL(uploadFile?.raw)
        PSD.fromURL(url).then((psd:any) => {
           
            board.value = psd.tree().export()
            // console.log(psd.tree())
            // console.log(psd.tree().children())
            showElementHandler(psd.tree().children())
        })
    }
}
const showElementHandler= (items:any)=>{
    items.forEach((x:any,i:number)=>{
        // if(x.layer.vectorMask){
        //     //x.layer.vectorMask().export()
        //     //console.log(x.layer.vectorMask(),x.layer.vectorMask().export())
        //     const paths = x.layer.vectorMask().export().paths;
        //     let color = getFillColor(x)
        //     const convertedPath: any[] = []
        //     paths.forEach((path:any) => {
        //       // 转换控制点的位置
        //       // 这里的 document 为psd.js导出的psd文档对象
        //       const { recordType, numPoints } = path;
        //       if(!path.preceding) return
        //       const {
        //         preceding,
        //         anchor,
        //         leaving
        //       } = parsePath(path, board.value.document);  // 控制点的位置转换成了像素位置

        //       convertedPath.push({
        //         preceding,
        //         anchor,
        //         leaving
        //       });
        //     });
        //     toPath(convertedPath,color,x.layer)
        // }
        if(x.layer.visible){
            zIndex.value--
            if(x.layer.typeTool){
              let f = x.layer.typeTool().export()
              const { left, top, width, height, value, font,transform } = f
              const { colors, styles, alignment,sizes,names,weights } = font
              let fontSize = 24.0
              if (sizes && sizes[0]) {
                if (transform.yy !== 1) {
                  fontSize = (Math.round((sizes[0] * transform.yy) * 100) * 0.01)
                } else { // transform.yy为1时，sizes[0]的值就是字体显示大小的值，不须要计算
                  fontSize = sizes[0]
                }
              }
              const StyleSheet = x.layer.adjustments.typeTool.obj.engineData.EngineDict.StyleRun.RunArray[0].StyleSheet || {}
              const { StyleSheetData } = StyleSheet
              const tracking = fontSize * (StyleSheetData.Tracking / 1000)
              const lineHeight = StyleSheetData.Leading
              let leading = (Math.round((lineHeight * transform.yy) * 100) * 0.01) / fontSize
              let objectEFFFects = x.layer.objectEffects?x.layer.objectEffects():null
              var div = document.createElement("div");
              console.log(f,x,objectEFFFects)
              div.innerText = value
              div.style.top = x.coords.top+"px"
              div.style.right = x.coords.right+"px"
              div.style.bottom = x.coords.bottom+"px"
              div.style.left = x.coords.left+"px"
              div.style.width = (x.layer.width+30)+"px"
              div.style.height = x.layer.height+"px"
              div.style.zIndex = zIndex.value.toString()
              div.style.opacity = (parseFloat(x.layer.opacity)/255.0).toFixed(2)
              div.style.textAlign = alignment[0]
              div.style.fontSize = fontSize+"px"
              div.style.fontFamily = names.join(',')
              div.style.writingMode = Ornts[x.layer.adjustments.typeTool.obj.textData.Ornt.value]
              div.style.color = `rgba(${colors[0][0]},${colors[0][1]},${colors[0][2]},${(parseFloat(colors[0][3])/255.0).toFixed(2)})`
              div.style.letterSpacing = tracking+"px"
              div.style.lineHeight = leading+""
              div.style.fontWeight = weights[0]
              if(font.textDecoration){
                div.style.textDecoration = font.textDecoration[0]
                div.style.textUnderlineOffset = '20px'
              }
              if(StyleSheetData.Strikethrough){
                div.style.textDecoration += ' line-through'
              }
              if(objectEFFFects && objectEFFFects.data?.DrSh.enab){
                div.style.textShadow=getShadows(objectEFFFects)
              }
              if(objectEFFFects && objectEFFFects.data?.GrFl.enab){
                div.style.backgroundImage = getGradient(objectEFFFects)
                //div.style["-webkit-background-clip"] = 'text'
                div.className='text-mask'
                //div.style.backgroundSize = (objectEFFFects.data.GrFl["Scl "].value/100*x.layer.width)+"px "+(objectEFFFects.data.GrFl["Scl "].value/100*x.layer.height)+"px"
                // div.style.backgroundPositionX = objectEFFFects.data.GrFl.Ofst.Hrzn.value+"px"
                // div.style.backgroundPositionY = objectEFFFects.data.GrFl.Ofst.Vrtc.value+"px"
                div.style.backgroundPosition = 'center center'
                div.style.backgroundColor =  `rgba(${colors[0][0]},${colors[0][1]},${colors[0][2]},${(parseFloat(colors[0][3])/255.0).toFixed(2)})`
                div.style.backgroundRepeat = 'no-repeat'
                div.style.color = 'transparent',

                div.style.textShadow='unset'
              }
              div.setAttribute("id","layer_text_"+zIndex.value)
              document.getElementById('ImageContainer')?.appendChild(div);
            }else if(x.width && x.width>0){
                try {
                    var img = document.createElement("img");
                    img.src = x.layer.image.toBase64()
                    img.style.top = x.coords.top+"px"
                    img.style.right = x.coords.right+"px"
                    img.style.bottom = x.coords.bottom+"px"
                    img.style.left = x.coords.left+"px"
                    img.style.zIndex = zIndex.value.toString()
                    img.style.opacity = (parseFloat(x.layer.opacity)/255.0).toFixed(2)
                    img.setAttribute("id","layer_image_"+zIndex.value)
                    document.getElementById('ImageContainer')?.appendChild(img);
                } catch (error) {
                    
                }
            }
            if(x._children && x._children.length>0){
                showElementHandler(x._children)
            }
        }
        prevLayer.value=x
    })
}
const getShadows = (drsh:any)=>{
  const { DrSh } = drsh.data
                
  const clrStr = JSON.stringify(DrSh['Clr ']).split(',')
  let r:string = '0'
  let g:string = '0'
  let b:string = '0'
  clrStr.forEach(item => {
    if (item.indexOf('Rd') !== -1) {
      r = item.replace('"Rd  ":', '')
    } else if (item.indexOf('Bl') !== -1) {
      b = item.replace('"Bl  ":', '').replace('}', '')
    } else if (item.indexOf('Grn') !== -1) {
      g = item.replace('"Grn ":', '')
    }
  })
  const angle = DrSh.lagl.value
  const distance = DrSh.Dstn.value
  var angleInRadians = angle * Math.PI / 180;
  const shadowColor = `rgba(${parseInt(r)},${parseInt(g)},${parseInt(b)},${DrSh.Opct.value / 100})`
  const x =Math.round(distance * Math.cos(angleInRadians));
  const y = Math.round(distance * Math.sin(angleInRadians));
  
  return x + "px " + y + "px " + DrSh.blur.value + "px " + shadowColor;
}
const getGradient=(obj:any)=>{
  const { GrFl } = obj.data
  const angle = GrFl.Angl.value-90
  let linear = `linear-gradient(${angle}deg `
  let intr = GrFl.Grad.Intr
  GrFl.Grad.Clrs.forEach((x:any,i:number)=>{
    const clrStr = JSON.stringify(x['Clr ']).split(',')
    let r:string = '0'
    let g:string = '0'
    let b:string = '0'
    clrStr.forEach(item => {
      if (item.indexOf('Rd') !== -1) {
        r = item.replace('"Rd  ":', '')
      } else if (item.indexOf('Bl') !== -1) {
        b = item.replace('"Bl  ":', '').replace('}', '')
      } else if (item.indexOf('Grn') !== -1) {
        g = item.replace('"Grn ":', '')
      }
    })
    const color = 
    linear+=`, rgba(${parseInt(r)},${parseInt(g)},${parseInt(b)},${GrFl.Opct.value / 100})`
    //linear-gradient(90deg, #FFF 0%, 18% ,#e5b8a4 36%, 68%, #FFF)
    let cent="",posi = ""
    if(i<GrFl.Grad.Clrs.length-1){
      posi = Math.ceil(x.Lctn*100/intr)+"%"
      cent = Math.ceil((x.Lctn + ((GrFl.Grad.Clrs[i+1].Lctn - x.Lctn)*x.Mdpn/100))*100/intr)+"%"
      linear+=` ${posi}, ${cent}`
    }
  })
  linear+=")"

  console.log(GrFl)
  return linear;
}
const getFillColor = (node:any) => {
    if(!node.layer.solidColor) return
    const solidColorData = node.layer.solidColor();
    let rgb = [solidColorData.r,solidColorData.g,solidColorData.b]
    
    return rgbaToHex(rgb)??''
//   return colorHex([
//     Math.round(clr["Rd "]),
//     Math.round(clr["Grn "]),
//     Math.round(clr["Bl "]),
//   ]);
   
};
const rgbaToHex = (rgba: number[]): string => {
  let hex = '#';
  for (const i of rgba) {
    hex += i.toString(16).padStart(2, '0');
  }
  return hex;
}
const signed = (n:any) => {
  let num = n;
  if (num > 0x8f) {
    num = num - 0xff - 1;
  }

  return num;
}
const getPathPosition = (pathNode:any) => {
  const {
    vert,
    horiz
  } = pathNode;

  return {
    x: signed(horiz),
    y: signed(vert)
  };
}
const parsePath = function (path:any, {width,height}:any) {
  const {
    preceding,
    anchor,
    leaving
  } = path;
  
  const precedingPos = getPathPosition(preceding);
  const anchorPos = getPathPosition(anchor);
  const leavingPos = getPathPosition(leaving);

  // relX 和 relY 保留了PSD中原始数据。
  return {
    preceding: {
      relX: precedingPos.x,
      relY: precedingPos.y,
      x: Math.round(width * precedingPos.x),
      y: Math.round(height * precedingPos.y)
    },
    anchor: {
      relX: anchorPos.x,
      relY: anchorPos.y,
      x: Math.round(width * anchorPos.x),
      y: Math.round(height * anchorPos.y)
    },
    leaving: {
      relX: leavingPos.x,
      relY: leavingPos.y,
      x: Math.round(width * leavingPos.x),
      y: Math.round(height * leavingPos.y)
    }
  };
};
const toPath = (paths:Array<any>, fill:any,node:any) => {
  let head:any;
  const data = [] as Array<any>;

  paths.forEach((path:any, index:number) => {
    const { preceding, anchor, leaving } = path;
    if (index < paths.length - 1) {
      if (index > 0) {  // 中间节点
        data.push(`${preceding.x}, ${preceding.y} ${anchor.x}, ${anchor.y} ${leaving.x}, ${leaving.y}`);
      } else {  // 记录第一个节点，用于在关闭路径的时候使用
        head = path;
        data.push(`M ${anchor.x}, ${anchor.y} C${leaving.x}, ${leaving.y}`);
      }
    } else {
      data.push(`${preceding.x}, ${preceding.y} ${anchor.x}, ${anchor.y} ${leaving.x}, ${leaving.y} ${head.preceding.x}, ${head.preceding.y} ${head.anchor.x}, ${head.anchor.y} Z`);
    }
  });
  let svg =  document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
  var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  zIndex.value--
  path.setAttribute('d',data.join(" "))
  path.setAttribute('fill',fill)
  path.setAttribute("width", node.width.toString());
  path.setAttribute("height", node.height.toString());
  g.appendChild(path);
  g.setAttribute("width", node.width.toString());
  g.setAttribute("height", node.height.toString());
  svg.appendChild(g);
  svg.setAttribute('viewBox',`0 0 ${node.width} ${node.height}`); 
  svg.style.width=node.width+"px"
  svg.style.height=node.height+"px"
  svg.style.top = node.top+"px"
  svg.style.right = node.right+"px"
  svg.style.bottom = node.bottom+"px"
  svg.style.left = node.left+"px"
  svg.style.zIndex = zIndex.value.toString()
  let prevNode = document.getElementById("layer_image_"+(zIndex.value+1))
  if(prevNode){
    var pattern = document.createElementNS("http://www.w3.org/2000/svg", "pattern");
    pattern.setAttribute("id", "pattern_"+zIndex.value);
    pattern.setAttribute("patternUnits", "userSpaceOnUse");
    pattern.setAttribute("width", node.width.toString());
    pattern.setAttribute("height", node.height.toString());
    var image = document.createElementNS("http://www.w3.org/2000/svg", "image");
    image.setAttribute("xlink:href", prevNode.getAttribute("src")??'');
    image.setAttribute("width", prevLayer.value.width.toString());
    image.setAttribute("height", prevLayer.value.height.toString());
    image.setAttribute("x", prevLayer.value.coords.left.toString());
    image.setAttribute("y", prevLayer.value.coords.top.toString());
    pattern.appendChild(image);
    path.setAttribute("fill", "pattern_"+zIndex.value);
    svg.appendChild(pattern);
    // img.style.top = x.coords.top+"px"
    //                 img.style.right = x.coords.right+"px"
    //                 img.style.bottom = x.coords.bottom+"px"
    //                 img.style.left = x.coords.left+"px"
    //                 img.style.zIndex = zIndex.value.toString()
    //                 img.style.opacity = (parseFloat(x.layer.opacity)/255.0).toFixed(2)
    prevNode.remove()
  }

  //svg.appendChild(path)
  //console.log(node.width+"px",node.height+"px")
  document.getElementById('ImageContainer')?.appendChild(svg)
  //return `<path d="${data.join(' ')}" fill="${fill}" />`;
}
const toPathHandler = (paths:any, fill:any,node:any) => {
  let head:any;
  const data = [] as Array<any>;
  paths.forEach((path:any, index:number) => {
    
    if(!path.preceding || !path.anchor || !path.leaving) return
    let newPath = parsePath(path,node)
    const { preceding, anchor, leaving } = newPath;
    if (index < paths.length - 1) {
      if (head) {
        // 中间节点
        data.push(
          `${preceding.x}, ${preceding.y} ${anchor.x}, ${anchor.y} ${leaving.x}, ${leaving.y}`
        );
      } else {
        // 记录第一个节点，用于在关闭路径的时候使用
        head = newPath;
        data.push(`M ${anchor.x}, ${anchor.y} C${leaving.x}, ${leaving.y}`);
      }
    } else {
      data.push(`${preceding.x}, ${preceding.y} ${anchor.x}, ${anchor.y} ${leaving.x}, ${leaving.y} ${head.preceding.x},
            ${head.preceding.y} ${head.anchor.x}, ${head.anchor.y} Z`);
    }
  });
  let svg =  document.createElementNS('http://www.w3.org/2000/svg', 'svg');
  var g = document.createElementNS('http://www.w3.org/2000/svg', 'g');
  var path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
  zIndex.value--
  path.setAttribute('d',data.join(" "))
  path.setAttribute('fill',fill)
  path.setAttribute("width", node.width.toString());
  path.setAttribute("height", node.height.toString());
  g.appendChild(path);
  g.setAttribute("width", node.width.toString());
  g.setAttribute("height", node.height.toString());
  svg.appendChild(g);
  svg.setAttribute('viewBox',`0 0 ${node.width} ${node.height}`); 
  svg.style.width=node.width+"px"
  svg.style.height=node.height+"px"
  svg.style.top = node.top+"px"
  svg.style.right = node.right+"px"
  svg.style.bottom = node.bottom+"px"
  svg.style.left = node.left+"px"
  svg.style.zIndex = zIndex.value.toString()
  let prevNode = document.getElementById("layer_image_"+(zIndex.value+1))
  if(prevNode){
    var pattern = document.createElementNS("http://www.w3.org/2000/svg", "pattern");
    pattern.setAttribute("id", "pattern_"+zIndex.value);
    pattern.setAttribute("patternUnits", "userSpaceOnUse");
    pattern.setAttribute("width", node.width.toString());
    pattern.setAttribute("height", node.height.toString());
    var image = document.createElementNS("http://www.w3.org/2000/svg", "image");
    image.setAttribute("xlink:href", prevNode.getAttribute("src")??'');
    image.setAttribute("width", prevLayer.value.width.toString());
    image.setAttribute("height", prevLayer.value.height.toString());
    image.setAttribute("x", prevLayer.value.coords.left.toString());
    image.setAttribute("y", prevLayer.value.coords.top.toString());
    pattern.appendChild(image);
    path.setAttribute("fill", "pattern_"+zIndex.value);
    svg.appendChild(pattern);
    // img.style.top = x.coords.top+"px"
    //                 img.style.right = x.coords.right+"px"
    //                 img.style.bottom = x.coords.bottom+"px"
    //                 img.style.left = x.coords.left+"px"
    //                 img.style.zIndex = zIndex.value.toString()
    //                 img.style.opacity = (parseFloat(x.layer.opacity)/255.0).toFixed(2)
    prevNode.remove()
  }

  //svg.appendChild(path)
  //console.log(node.width+"px",node.height+"px")
  document.getElementById('ImageContainer')?.appendChild(svg)

  //return `<path d="${data.join(" ")}" fill="${fill}" />`;
};
const handleExceed: UploadProps['onExceed'] = (files, uploadFiles) => {
  ElMessage.warning(
    `The limit is 3, you selected ${files.length} files this time, add up to ${
      files.length + uploadFiles.length
    } totally`
  )
}
</script>
<style>
#ImageContainer *{
    position: absolute;
}
@font-face {
  font-family: FZCSJW--GB1-0;
  src: local('方正粗宋简体');
}
@font-face {
  font-family: MicrosoftYaHeiLight;
  src: local('Microsoft YaHei Light');
}
.text-mask{
  -webkit-background-clip: text;
}
</style>