// GeoTiff 地图文件处理
// todo load: leaflet

import JSZip from 'jszip'
import { fileUtils } from '@/utils/util.js'
import mapCanvas from '@/utils/mapCanvas.js'
import * as wasmMap from '@/pkg/common_wasm.js'
import {
	fromUrl,
	fromArrayBuffer,
	fromFile
} from 'geotiff'

// #ifdef APP-PLUS
// import io from '@/utils/io.js'
// #endif

let that = null
let dbHelper = null
let imgMap = null
export default {
	async handleMapInfo(context, mapInfo) {
		that = context
		dbHelper = that.$dbHelper		
		imgMap = that.$refs.imgMap
		console.log("[handleMapInfo]", context, mapInfo)
		console.log("[handleMapInfo] imgMap", imgMap)
		try {
			await dbHelper.openDB()
			
			const res = await this.dbGetMapInfo(mapInfo.shopid)
			let download = false
			let action = null
			let mapData = null
			if (res == null || res.length == 0) {
				console.warn('[handleMapInfo] 本地无匹配记录，需要下载地图')
				download = true
				action = 'insert'
			} else {
				const localMd5 = (res.zipImage != undefined) ? res.zipImage.md5 : res.zipImageMd5
				if (localMd5 != mapInfo.zipimage.md5) {
					console.warn('[handleMapInfo] MD5不同，需再次下载地图')
					download = true
					action = 'update'
				} else {
					console.log('[handleMapInfo] MD5相同，无需再次下载地图')
					download = false
					mapData = this.getMapDataFromDBres(res)
					// download = true // debug, will del
					// action = 'update' // debug, will del
				} 
			}
			
			if (download) {
				const zipData = await this.getZipFiles(mapInfo.zipimage.url)
				// const unzipFiles = await this.unzipMap(zipData)
				// console.log("[handleMapInfo] download", mapInfo, unzipFiles)
				const unzipFiles = ''
				await this.dbSaveMapInfo(mapInfo, zipData, unzipFiles, action)
				// mapData = unzipFiles[0].fileData
				mapData = zipData
			}
			
			await dbHelper.closeDB()
			
			// await this.parseMap(mapData)
			// await this.parseMap2(mapData)
			await this.loadMap(mapData)
			// return mapData
		} catch (err) {
			console.error('[handleMapInfo]', err)
		}
	},
	
	// 从指定的URL下载地图压缩包
	async getZipFiles(zipUrl) {
		console.log("[getZipFiles] zipUrl:", zipUrl)
		if (!(zipUrl.length > 0)) {
			console.log("[getZipFiles] err: zipUrl 为空")
			return
		}

		let [err, res] = await uni.request({
			url: zipUrl,
			timeout: 60000, // 超时时间，单位 ms
			responseType: 'arraybuffer', // 设置响应的数据类型。合法值：text、arraybuffer
		});

		console.log("[getZipFiles]", res)
		return res.data
	},

	// 解包并获取包内的各文件内容数据 (arraybuffer格式)
	async unzipMap(zipData) {
		// console.log("[unzipMap] zipData: ", zipData)
		if (zipData == undefined || (!(zipData.byteLength > 0))) {
			console.log("[unzipMap] err: zipData 为空")
			return
		}
		console.log("[unzipMap] 压缩包大小（字节） zipData.byteLength:", zipData.byteLength)

		try {
			let jsZip = new JSZip()
			let zip = await jsZip.loadAsync(zipData)
			// console.log('zip.files', zip.files)
			let unzipFiles = []
			let i = 0
			for (let fileName in zip.files) { // filename为压缩包中的文件名
				console.log('[unzipMap] fileName', fileName)
				
				let isImage = fileUtils.isTypeImage(fileName)
				let fileData = ''
				let dataType = ''
				// 获取文件内容，可以使用string、arraybuffer等格式
				if (isImage) {
					fileData = await zip.file(fileName).async('arraybuffer')
					dataType = 'arraybuffer'
				} else {
					fileData = await zip.file(fileName).async('string')
					dataType = 'string'
				}
				
				// console.log('[unzipMap] content', content)
				
				unzipFiles[i] = {
					fileName: fileName,
					fileData: fileData,
					dataType: dataType
				}
				i++
			}
			return unzipFiles
		} catch(err) {
			console.error('[unzipMap]', err)
		}
	},
	
	// 将地图信息保存到本地数据库中
	async dbSaveMapInfo(mapInfo, zipData, unzipFiles='', action='insert') {
		// #ifdef H5
		await this.dbSaveMapInfo_H5(mapInfo, zipData, unzipFiles, action)
		// #endif
		
		// #ifdef APP-PLUS
		await this.dbSaveMapInfo_APP(mapInfo, zipData, unzipFiles, action)
		// #endif
	},
	
	// [H5端] 将地图信息保存到本地浏览器 dbHelper 数据库中
	async dbSaveMapInfo_H5(mapInfo, zipData, unzipFiles, action) {
		// console.log("[dbSaveMapInfo_H5]", mapInfo, unzipFiles)
		
		let storeName = 'mapInfo'
		let data = {
			shopId: mapInfo.shopid,
			mapName: mapInfo.mapname,
			zipImage: {
				url: mapInfo.zipimage.url,
				md5: mapInfo.zipimage.md5,
			},
			zipData: zipData,
			unzipFiles: unzipFiles
		}
		
		try {
			if (action == 'insert') {
				await dbHelper.insertData(storeName, data)
			} else if (action == 'update') {
				await dbHelper.updateData(storeName, data)
			} else {
				console.warn('[dbSaveMapInfo_H5] 参数 action 非法: ' + action)
			}
		} catch(err) {
			console.error('[dbSaveMapInfo_H5]', err)
		}
	},

	// [APP端] 将地图信息保存到手机中的 SQLITE 数据库中
	async dbSaveMapInfo_APP(mapInfo, zipData, unzipFiles, action) {
		// console.log("[dbSaveMapInfo_APP]", mapInfo, unzipFiles)
		
		let tableName = 'mapInfo'
		let zipFileKey = 'map_' + mapInfo.shopid
		let zipFileName = ''
		if (unzipFiles.length > 0) {
			zipFileName = unzipFiles[0].fileName
			// let zipFilePath = mapInfo.shopid + '_' + unzipFiles[0].fileName
			let zipFileData = uni.arrayBufferToBase64(unzipFiles[0].fileData)
			
			// await io.write(zipFilePath, zipFileData)
			uni.setStorageSync(zipFileKey, zipFileData);
			
			console.log("[dbSaveMapInfo_APP] setStorageSync Key:", zipFileKey)
			console.log("[dbSaveMapInfo_APP] setStorageSync data.fileData length:", unzipFiles[0].fileData.byteLength)
			
			// let zipFile = uni.base64ToArrayBuffer(uni.getStorageSync(zipFileKey));
			// console.log("-----> getStorageSync Key", zipFileKey)
			// console.log("-----> getStorageSync data.fileData length", zipFile.byteLength)
		}
		
		let data = {
			shopId: mapInfo.shopid,
			mapName: mapInfo.mapname,
			zipImageUrl: mapInfo.zipimage.url,
			zipImageMd5: mapInfo.zipimage.md5,
			zipFileName: zipFileName,
			zipFileKey: zipFileKey,
			// zipFilePath: zipFilePath,
		}
		
		try {
			if (action == 'insert') {
				await dbHelper.insertData(tableName, data)
			} else if (action == 'update') {
				let wsql = 'shopId = ' + data.shopId
				await dbHelper.updateData(tableName, data, wsql)
			} else {
				console.warn('[dbSaveMapInfo_APP] 参数 action 非法: ' + action)
			}
		} catch(err) {
			console.error('[dbSaveMapInfo_APP]', err)
		}
	},
	
	async dbGetMapInfo(shopid) {
		let res = null
		
		// #ifdef H5
		res = await this.dbGetMapInfo_H5(shopid)
		// #endif
		
		// #ifdef APP-PLUS
		res = await this.dbGetMapInfo_APP(shopid)
		// #endif
		
		return res
	},
	
	// [H5端] 
	async dbGetMapInfo_H5(shopid) {
		console.log("[dbGetMapInfo_H5]", shopid)
		let storeName = 'mapInfo'
		let key = shopid
		
		try {
			let data = await dbHelper.getDataByKey(storeName, key)
			return data
		} catch(err) {
			console.error('[dbGetMapInfo_H5]', err)
		}
	},

	// [APP端] 
	async dbGetMapInfo_APP(shopid) {
		console.log("[dbGetMapInfo_APP] shopid", shopid)
		let tableName = 'mapInfo'
		let key = shopid
		
		try {
			let data = await dbHelper.getDataByKey(tableName, key)
			
			if (data != '' && data.zipFileKey.length > 0) {
				// let zipFileData = uni.base64ToArrayBuffer(await io.read(data.zipFilePath))
				let zipFileData = uni.base64ToArrayBuffer(uni.getStorageSync(data.zipFileKey))
				console.log("[dbGetMapInfo_APP] getStorageSync Key", data.zipFileKey)
				console.log("[dbGetMapInfo_APP] getStorageSync data length", zipFileData.byteLength)
				
				data.zipFileData = zipFileData
			}
			// console.log("[dbGetMapInfo_APP] data", data)
			return data
		} catch(err) {
			console.error('[dbGetMapInfo_APP]', err)
		}
	},
	
	getMapDataFromDBres(dbres) {
		let arrayBuffer = null
		
		// #ifdef H5
		// arrayBuffer = dbres.unzipFiles[0].fileData
		arrayBuffer = dbres.zipData
		// console.log('getMapDataFromDBres', dbres.unzipFiles[0].fileName, dbres.unzipFiles[0].fileData)
		// #endif
		
		// #ifdef APP-PLUS
		arrayBuffer = dbres.zipFileData
		// console.log('getMapDataFromDBres', dbres.zipFileName, dbres.zipFileData)
		// #endif
		
		return arrayBuffer
	},

	async parseMap(arrayBuffer) {
		// console.log("[parseMap]", arrayBuffer)
		// for(let i=0; i<30; i++) {
		// 	console.log(`[parseMap] arrayBuffer[${i}] ${arrayBuffer[i]}`)
		// }
		
		if (arrayBuffer == undefined || (!(arrayBuffer.byteLength > 0))) {
			console.log("[parseMap] err: arrayBuffer 为空")
			return
		}
		console.log("[parseMap] MAP文件大小（字节） arrayBuffer.byteLength: " + arrayBuffer.byteLength)
		try {
			// 加载 GeoTIFF 文件
			const tiff = await fromArrayBuffer(arrayBuffer)
			console.log("[parseMap] tiff", tiff)
			const image = await tiff.getImage()
			console.log("[parseMap] image", image)
			const width = image.getWidth();
			const height = image.getHeight();
			const tileWidth = image.getTileWidth();
			const tileHeight = image.getTileHeight();
			console.log(
				`[parseMap] width: ${width} height: ${height} tileWidth: ${tileWidth} tileHeight: ${tileHeight}`
			)
			// const samplesPerPixel = image.getSamplesPerPixel();

			// let canvas = this.$refs.canvasMap
			// canvas.width = width
			// canvas.height = height
			// let ctx = canvas.getContext('2d')

			// let ctx = uni.createCanvasContext('canvasMap', this)

			// 渲染图片
			// ctx.drawImage(image, 0, 0)
			// ctx.draw()
			// console.log('图片渲染完成')
			// return

			let imageData = new Uint8ClampedArray(width * height * 4)
			// console.log("imageData:", imageData)
			// let src = that
			image.readRasters().then(function(rasters) {
				// console.log("rasters:", rasters)
				// console.log("rasters:", JSON.stringify(rasters))
				for (let i = 0; i < width * height; i++) {
					let offset = i * 4
					// console.log("rasters[0]:", rasters[0][i])
					imageData[offset + 0] = rasters[0][i]
					imageData[offset + 1] = rasters[1][i]
					imageData[offset + 2] = rasters[2][i]
					imageData[offset + 3] = 255
				}

				uni.canvasPutImageData({
					canvasId: 'canvasMap',
					data: imageData,
					x: 0,
					y: 0,
					width: width,
					// height: 100,
					success(res) {
						console.log("[parseMap] canvasPutImageData res", res)
					},
					fail(err) {
						console.log("[parseMap] canvasPutImageData err", err)
					}
				})

				// ctx.draw()
			})
			
			// // when we are actually dealing with geo-data the following methods return
			// // meaningful results:
			// const origin = image.getOrigin();
			// const resolution = image.getResolution();
			// const bbox = image.getBoundingBox();
		} catch (err) {
			console.error("[parseMap] catch err:", err)
		}
	},
	
	async parseMap2(mapData) {
		let binaryData = [];
		binaryData.push(mapData);
		that.mapUrl = URL.createObjectURL(new Blob(binaryData));
		
		console.log("[parseMap2] imgMap", imgMap)
		// imgMap.src = URL.createObjectURL(new Blob(binaryData));
	},
	
	async loadMap(mapData) {
		try {
			let mapPackage = wasmMap.parse_map_package(new Uint8Array(mapData))
			console.log("[loadMap] mapPackage", mapPackage) 
			
			let binaryData = [];
			binaryData.push(mapPackage.map_image_data);
			that.mapUrl = URL.createObjectURL(new Blob(binaryData));
			
			return
			await mapCanvas.initCanvas('canvasMap', that)
			mapCanvas.handleDrawMap(that.mapUrl)
			
			// let offset = new wasmMap.Offset()
			// offset.x = 100
			// offset.y = 200
			// let position = mapPackage.pic_to_position(offset)
			// console.log("[loadMap] pic_to_position", offset, position)
			
			// let position2 = new wasmMap.Position()
			// position2.latitude = 36.67352331171326
			// position2.longitude = 117.1257123815962
			// let offset2 = mapPackage.position_to_pic(position2)
			// console.log("[loadMap] position_to_pic", position2, offset2)
			
			// 使用完毕后一定要调用free方法释放内存
			// position.free()
			// offset2.free()
			// mapPackage.free()
			
			// console.log("[loadMap] imgMap", imgMap)
		} catch (err) {
			console.error('[loadMap]', err)
		}
	}
}