import { Empty, Input, Modal } from 'antd'
import { Button, Upload, message } from 'antd'
import ImgCrop from 'antd-img-crop'
import { useEffect, useMemo, useRef, useState } from 'react'
import AMapLoader from '@amap/amap-jsapi-loader';
import style from './style.module.scss'
import { SceneType, SceneTypeDomain, SceneTypePaths } from 'constant';
import { base64ToBlob, getHref, drawImage } from 'utils';
import { asyncLoading } from 'components/loading';
import { RedoOutlined } from '@ant-design/icons';
import { fetchTaggings } from 'api'
import { SortTransfer } from './sort-transfer'
import { BoardType, BoardTypeDesc } from 'api'

import type { Tagging } from 'api'
import type { UploadProps } from 'antd'

const domScreenshot = async (dom: HTMLElement) => {
  const canvas = (dom.tagName.toUpperCase() === 'CANVAS' ? dom : dom.querySelector('canvas')) as HTMLCanvasElement
  return new Promise<Blob | null>(resolve => {
    if (!canvas) {
      return resolve(null)
    }
    canvas.toBlob(resolve)
  })
}

type SelectImageProps = {
  onClose: () => void
  onSave: (url: Blob | null, tagging: Tagging[]) => void
}


let AMap: any
AMapLoader.load({ 
  plugins: ['AMap.PlaceSearch'],
  key: 'e661b00bdf2c44cccf71ef6070ef41b8', 
  version: '2.0',
}).then(result => AMap = result)

type MapInfo = { lat: number, lng: number, zoom: number }
export const SelectMap = (props: SelectImageProps) => {
  const [open, setOpen] = useState(true)
  const [info, setInfo] = useState<MapInfo>()
  const [keyword, setKeyword] = useState('')
  const mapEle = useRef<HTMLDivElement>(null)
  const searchResultEle = useRef<HTMLDivElement>(null)
  const searchAMap = useRef<any>()

  const onSubmit = async () => {
    if (mapEle.current) {
      const blob = await domScreenshot(mapEle.current)
      await props.onSave(blob, [])
      setOpen(false)
    }
  }

  const renderInfo = info && <div className={style['def-map-info']}>
    <p><span>经度</span>{ info.lat }</p>
    <p><span>维度</span>{ info.lng }</p>
    <p><span>缩放级别</span>{ info.zoom }</p>
  </div>

  useEffect(() => {
    if (!mapEle.current) {
      return;
    }
    const map = new AMap.Map(mapEle.current, {
      WebGLParams: {
        preserveDrawingBuffer: true
      },
      resizeEnable: true
    })
    const placeSearch = new AMap.PlaceSearch({
      pageSize: 5, 
      pageIndex: 1, 
      map: map, 
      panel: searchResultEle.current, 
      autoFitView: true 
    });
    const getMapInfo = (): MapInfo => {
      var zoom = map.getZoom(); //获取当前地图级别
      var center = map.getCenter();
      return {
        zoom,
        lat: center.lat,
        lng: center.lng
      }
    }
    //绑定地图移动与缩放事件
    map.on('moveend', () => setInfo(getMapInfo()));
    map.on('zoomend', () => setInfo(getMapInfo()));
    searchAMap.current = placeSearch

    return () => {
      searchAMap.current = null
      map.destroy()
    }
  }, [mapEle])

  useEffect(() => {
    keyword && searchAMap.current?.search(keyword)
  }, [keyword, searchAMap])

  return (
    <Modal 
      width="588px"
      title="选择地址" 
      open={open} 
      onCancel={() => setOpen(false)}
      onOk={() => asyncLoading(onSubmit())} 
      afterClose={props.onClose}
      okText="确定"
      cancelText="取消"
    >
      <div className={style['search-layout']}>
        <Input.Search
          allowClear
          placeholder="输入名称搜索" 
          onSearch={setKeyword}
          style={{ width: 350 }} 
        />
        <div 
          className={`${style['search-result']} ${keyword ? style['show']: ''}`} 
          ref={searchResultEle} 
        />
      </div>
      <div ref={mapEle} className={style['def-select-map']}></div>
      { renderInfo }
    </Modal>
  )
}

const getFuseUrl = (caseId: number) =>
  `${getHref(SceneTypeDomain[SceneType.SWMX]!, SceneTypePaths[SceneType.SWMX][0], { caseId: caseId.toString() })}&share=1#show/summary`


enum ImageType {
  FUSE,
  KANKAN,
  LASER
}
type FuseImageRet = { type: ImageType, blob: Blob | null }
const getFuseImage = async (iframe: HTMLIFrameElement) => {
  const iframeElement = iframe.contentWindow?.document.documentElement
  
  if (!iframeElement) {
    return null
  }
  const extIframe = iframeElement.querySelector('.external') as HTMLIFrameElement
  const targetIframe = extIframe || iframe
  const targetWindow: any = targetIframe.contentWindow
  const fuseCnavas = targetWindow.document.querySelector('.scene-canvas > canvas') as HTMLElement
  
  if (fuseCnavas) {
    const dataURL = await targetWindow.sdk.screenshot(targetIframe.offsetWidth, targetIframe.offsetHeight)
    const res = await fetch(dataURL)
    const blob = await res.blob()
    return { type: ImageType.FUSE, blob }
    // return domScreenshot(fuseCnavas).then(blob => ({ type: ImageType.FUSE, blob }))
  }
  const isLaser = targetWindow.document.querySelector('.laser-layer')

  if (isLaser) {
    const sdk = await targetWindow.__sdk
    return new Promise<FuseImageRet>(resolve => {
      sdk.scene.screenshot(540, 390).done((data: string) => {
        resolve({ type: ImageType.FUSE, blob: base64ToBlob(data) })
      })
    })
  } else {
    const sdk = targetWindow.__sdk
    return new Promise<FuseImageRet>(resolve => {
      sdk.Camera.screenshot([ {width: 540, height: 390, name: '2k' }],false).then((result: any)=>{
        resolve({ type: ImageType.KANKAN, blob: base64ToBlob(result[0].data) })
      })
    })
  }
}

export const SelectFuse = (props: SelectImageProps & { caseId: number }) => {
  const [open, setOpen] = useState(true)
  const [blob, setBlob] = useState<Blob | null>(null)
  const [tags, setTags] = useState<Tagging[]>([])
  const [selectTags, setSelectTags] = useState<string[]>([])
  const [addTagIds, setAddTagIds] = useState<string[]>([])
  const iframeRef = useRef<HTMLIFrameElement>(null)
  const coverUrl = useMemo(() => blob && URL.createObjectURL(blob), [blob])
  const url = useMemo(() => getFuseUrl(props.caseId), [props.caseId])
  const addTags = useMemo(() => addTagIds.map(id => tags.find(tag => tag.tagId.toString() === id)!), [addTagIds, tags])
  const mockData = useMemo(() => tags.map(tag => ({ 
    data: tag, 
    key: tag.tagId.toString()
  })), [tags])


  useEffect(() => {
    fetchTaggings(props.caseId.toString()).then(setTags)
  }, [props.caseId])

  const onSubmit = async () => {
    const filterTags = addTagIds.map(id => tags.find(tag => tag.tagId.toString() === id)!)
    props.onSave(blob, filterTags)
    setOpen(false)
  }
  const getCover = async () => {
    if (iframeRef.current) {
      const fuseImage = await getFuseImage(iframeRef.current)
      if (!fuseImage?.blob) {
        return;
      } else if (fuseImage.type !== ImageType.FUSE) {
        setBlob(fuseImage.blob)
        return;
      }

      const img = new Image()
      img.src = URL.createObjectURL(fuseImage.blob)
      await new Promise(resolve => img.onload = resolve)

      const $canvas = document.createElement('canvas')
      $canvas.width = img.width
      $canvas.height = img.height

      const ctx = $canvas.getContext('2d')!
      ctx.drawImage(img, 0, 0, img.width, img.height)

      const contentDoc = iframeRef.current.contentWindow!.document
      const hotItems = Array.from(contentDoc.querySelectorAll('.hot-item')) as HTMLDivElement[]
      hotItems.forEach(hot => {
        const hotTitle = (hot.querySelector('.tip') as HTMLDivElement).innerText
        const index = addTags.findIndex(tag => tag.tagTitle.trim() === hotTitle.trim())
        if (index !== -1) {
          const bound = hot.getBoundingClientRect()
          const size = (img.width / 540) * 32

          const left = bound.left + size / 2
          const top = bound.top + size / 2
          ctx.save()
          ctx.translate(left, top)
          ctx.beginPath()
          ctx.arc(0, 0, size / 2, 0, 2 * Math.PI)
          ctx.strokeStyle = '#000'
          ctx.fillStyle = '#fff'
          ctx.stroke()
          ctx.fill()
          ctx.beginPath()
          ctx.fillStyle = '#000'
          ctx.textAlign = 'center'
          ctx.textBaseline = 'middle'
          ctx.font = `normal ${size / 2}px serif`
          ctx.fillText((index + 1).toString(), 0, 0)
          ctx.restore()
        }
      })
      
      const $ccanvas = document.createElement('canvas')
      $ccanvas.width = 540 
      $ccanvas.height = 390
      const cctx = $ccanvas.getContext('2d')!
      drawImage(
        cctx, 
        $ccanvas.width,
        $ccanvas.height,
        $canvas,
        img.width,
        img.height,
        0, 0
      )
      
      console.error('???')
      const blob = await new Promise<Blob | null>(resolve => $ccanvas.toBlob(resolve, 'png'))
      setBlob(blob)
    }
  }


  return (
    <Modal 
      width="1500px"
      title="选择户型图" 
      open={open} 
      onCancel={() => setOpen(false)}
      onOk={() => asyncLoading(onSubmit())} 
      afterClose={props.onClose}
      okText="确定"
      cancelText="取消"
    >
      <div className={style['house-layout']}>
        <div className={style['iframe-layout']}>
          <iframe src={url} ref={iframeRef} title="fuce-code" />
        </div>
        <div className={style['content-layout']}>
          <div className={style['house-tags']}>
            <h4>请选择要同步到现场图的标注：</h4>  
            <div className={style['tagging-transfer']}>
              <SortTransfer
                dataSource={mockData}
                titles={['所有', '需要']}
                targetKeys={addTagIds}
                selectedKeys={selectTags}
                onChange={setAddTagIds}
                onSelectChange={(sKeys, tKeys) => setSelectTags([...sKeys, ...tKeys])}
                onChangeSort={tags => setAddTagIds(tags.map(tag => tag.data.tagId.toString()))}
              />
            </div>
          </div>  
          <div className={style['house-image-layout']}>
            <h4>户型图：<RedoOutlined className='icon' onClick={getCover} /></h4>
            <div className={style['house-image']}>
              <div>
                { coverUrl ? <img src={coverUrl} alt="预览图" /> : <Empty image={Empty.PRESENTED_IMAGE_SIMPLE} /> }
              </div>
            </div>
          </div>  
        </div>
      </div>
    </Modal>
  )
}



type DfUploadCropProp = Partial<SelectImageProps> & {
  type: BoardType
  caseId: number
}
export const DfUploadCrop = ({ type, caseId, onClose, onSave }: DfUploadCropProp) => {
  const onUpload: UploadProps['beforeUpload'] = async file => {
    const filename = file.name
    
    const ext = filename.substring(filename.lastIndexOf('.'))
    const isImg = ['.png', '.jpg'].includes(ext.toLocaleLowerCase())
    if (!isImg) {
      message.error('只能上传png或jpg文件')
      return Upload.LIST_IGNORE
    } else if (file.size > 100 * 1024 * 1024) {
      message.error('大小在100MB以内')
      return Upload.LIST_IGNORE
    }
    const img = new Image();
    img.src = URL.createObjectURL(file);
    await new Promise(resolve => {
      img.onload = resolve
    })
    const $canvas = document.createElement("canvas");
    $canvas.width = 540;
    $canvas.height = 390;
    const ctx = $canvas.getContext("2d")
    ctx?.drawImage(img, 0, 0, 540, 390);
    const blob = await domScreenshot($canvas);
    onSave && onSave(blob, [])
    return Upload.LIST_IGNORE
  }

  return (
    <ImgCrop rotationSlider modalTitle={"裁剪" + BoardTypeDesc[type]} aspect={540 / 390} minZoom={1} maxZoom={5}>
      <Upload beforeUpload={onUpload}  multiple={false} accept="png">
          <Button type="primary" ghost block>上传{ BoardTypeDesc[type] }</Button>
      </Upload>
    </ImgCrop>
  )
}