/**
 * MinIO 文件上传工具
 * 使用 AWS Signature V4 签名，通过 plus.net.XMLHttpRequest PUT 直传
 */

import sha256 from 'js-sha256'

// ====== Polyfill: atob ======
if (typeof atob === 'undefined') {
  var atob = function (input) {
    var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'
    input = input.replace(/=+$/, '')
    var output = ''
    for (var bc = 0, bs = 0, buffer, i = 0; buffer = input.charAt(i++); ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0) {
      buffer = chars.indexOf(buffer)
    }
    return output
  }
}

// ====== MinIO 配置 ======
var CFG = {
  endpoint: 'shxy.image.yushutx.com',
  accessKey: 'minioadmin',
  secretKey: 'minioadmin',
  bucket: 'scan-book',
  region: 'us-east-1',
  protocol: 'https'
}

// ====== 工具函数 ======

function pad(n) { return n < 10 ? '0' + n : '' + n }

function hmacRaw(key, msg) {
  return hexToBytes(sha256.hmac(key, msg))
}

function hexToBytes(hex) {
  var bytes = []
  for (var i = 0; i < hex.length; i += 2) {
    bytes.push(parseInt(hex.substring(i, i + 2), 16))
  }
  return new Uint8Array(bytes)
}

function bytesToHex(bytes) {
  var s = ''
  for (var i = 0; i < bytes.length; i++) {
    s += '0123456789abcdef'[(bytes[i] >> 4) & 0xf]
    s += '0123456789abcdef'[bytes[i] & 0xf]
  }
  return s
}

function sha256Hex(s) { return sha256(s) }

// ====== AWS V4 签名 ======

function buildAuthHeader(objectKey, date, contentType, contentSha256) {
  var dateStr = date.getUTCFullYear() + pad(date.getUTCMonth() + 1) + pad(date.getUTCDate())
  var amzDate = dateStr + 'T' + pad(date.getUTCHours()) + pad(date.getUTCMinutes()) + pad(date.getUTCSeconds()) + 'Z'

  var host = CFG.endpoint
  var canonicalUri = '/' + CFG.bucket + '/' + objectKey

  var signedHeadersList = ['content-type', 'host', 'x-amz-content-sha256', 'x-amz-date']
  var canonicalHeaders =
    'content-type:' + contentType + '\n' +
    'host:' + host + '\n' +
    'x-amz-content-sha256:' + contentSha256 + '\n' +
    'x-amz-date:' + amzDate + '\n'
  var signedHeadersStr = signedHeadersList.join(';')

  var canonicalRequest =
    'PUT\n' + canonicalUri + '\n\n' + canonicalHeaders + '\n' + signedHeadersStr + '\n' + contentSha256

  var credentialScope = dateStr + '/' + CFG.region + '/s3/aws4_request'
  var stringToSign = 'AWS4-HMAC-SHA256\n' + amzDate + '\n' + credentialScope + '\n' + sha256Hex(canonicalRequest)

  var signingKey = hmacRaw('AWS4' + CFG.secretKey, dateStr)
  signingKey = hmacRaw(signingKey, CFG.region)
  signingKey = hmacRaw(signingKey, 's3')
  signingKey = hmacRaw(signingKey, 'aws4_request')
  var signature = bytesToHex(hmacRaw(signingKey, stringToSign))

  var authHeader = 'AWS4-HMAC-SHA256 Credential=' + CFG.accessKey + '/' + credentialScope +
    ', SignedHeaders=' + signedHeadersStr + ', Signature=' + signature

  return { authHeader: authHeader, amzDate: amzDate }
}

// ====== 文件读取（readAsDataURL → base64 → uni.base64ToArrayBuffer） ======

function readFileAsBase64(filePath) {
  return new Promise(function (resolve, reject) {
    if (typeof plus !== 'undefined' && plus.io && plus.io.FileReader) {
      plus.io.resolveLocalFileSystemURL(filePath, function (entry) {
        entry.file(function (file) {
          var reader = new plus.io.FileReader()
          reader.onloadend = function (e) {
            var data = e.target.result
            if (data.indexOf(',') > -1) data = data.split(',')[1]
            resolve(data)
          }
          reader.onerror = function () { reject(new Error('FileReader失败')) }
          reader.readAsDataURL(file)
        }, function () { reject(new Error('获取文件对象失败')) })
      }, function (err) {
        reject(new Error('resolveLocalFileSystemURL失败: ' + JSON.stringify(err)))
      })
      return
    }
    reject(new Error('plus.io 不可用'))
  })
}

// ====== 时间同步 ======

var _cachedTimeOffset = null

function syncServerTime() {
  return new Promise(function (resolve) {
    console.log('【MinIO时间同步】开始...')
    if (typeof plus !== 'undefined' && plus.net && plus.net.XMLHttpRequest) {
      try {
        var xhr = new plus.net.XMLHttpRequest()
        var timer = setTimeout(function () {
          console.warn('【MinIO时间同步】超时')
          xhr.abort()
          resolve(new Date())
        }, 10000)

        xhr.onreadystatechange = function () {
          if (xhr.readyState === 4) {
            clearTimeout(timer)
            try {
              var dateStr = xhr.getResponseHeader('Date')
              console.log('【MinIO时间同步】readyState=4, status:', xhr.status, ', Date头:', dateStr)
              if (dateStr) {
                var serverMs = Date.parse(dateStr)
                if (!isNaN(serverMs)) {
                  _cachedTimeOffset = serverMs - Date.now()
                  console.log('【MinIO时间同步】成功! 偏移:', _cachedTimeOffset, 'ms')
                  resolve(new Date(Date.now() + _cachedTimeOffset))
                  return
                }
              }
            } catch (e) {
              console.warn('【MinIO时间同步】解析异常:', e)
            }
            resolve(new Date())
          }
        }
        xhr.open('GET', CFG.protocol + '://' + CFG.endpoint + '/')
        xhr.send()
        return
      } catch (e) {
        console.warn('【MinIO时间同步】创建XHR失败:', e)
      }
    }
    resolve(new Date())
  })
}

function getServerDate() {
  if (_cachedTimeOffset !== null) {
    return new Date(Date.now() + _cachedTimeOffset)
  }
  return new Date()
}

// ====== 上传 ======

export function uploadImage(filePath, typeDir) {
  if (typeDir === undefined) typeDir = 'Isbn'
  return new Promise(function (resolve, reject) {
    syncServerTime().then(function () {
      readFileAsBase64(filePath).then(function (base64) {
        // base64 → ArrayBuffer
        var binaryStr = atob(base64)
        var bytes = new Uint8Array(binaryStr.length)
        for (var i = 0; i < binaryStr.length; i++) {
          bytes[i] = binaryStr.charCodeAt(i)
        }
        var arrayBuffer = bytes.buffer
        var payloadHash = 'UNSIGNED-PAYLOAD'

        var now = getServerDate()
        var datePath = now.getFullYear() + '-' + pad(now.getMonth() + 1) + '-' + pad(now.getDate())
        var ext = (filePath.match(/\.(\w+)$/) || [])[1] || 'jpg'
        ext = ext.toLowerCase()
        var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
          var r = Math.random() * 16 | 0
          return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16)
        })
        var objectKey = datePath + '/' + typeDir + '/' + uuid + '.' + ext
        var ct = { jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', gif: 'image/gif', webp: 'image/webp', bmp: 'image/bmp' }
        var contentType = ct[ext] || 'image/jpeg'

        var sig = buildAuthHeader(objectKey, now, contentType, payloadHash)
        var url = CFG.protocol + '://' + CFG.endpoint + '/' + CFG.bucket + '/' + objectKey

        console.log('【MinIO上传】URL:', url)
        console.log('【MinIO上传】contentType:', contentType)
        console.log('【MinIO上传】dataSize:', arrayBuffer.byteLength, '字节')
        console.log('【MinIO上传】服务器时间:', now.toISOString())

        // 使用 uni.request PUT（App 环境中 ArrayBuffer 传输最可靠）
        uni.request({
          url: url,
          method: 'PUT',
          header: {
            'Content-Type': contentType,
            'X-Amz-Content-Sha256': payloadHash,
            'X-Amz-Date': sig.amzDate,
            'Authorization': sig.authHeader
          },
          data: arrayBuffer,
          success: function (res) {
            console.log('【MinIO上传】status:', res.statusCode)
            if (res.statusCode === 200) {
              console.log('【MinIO上传】成功:', url)
              resolve(url)
            } else {
              console.error('【MinIO上传】失败, HTTP:', res.statusCode, JSON.stringify(res.data || '').substring(0, 200))
              reject(new Error('上传失败: HTTP ' + res.statusCode))
            }
          },
          fail: function (err) {
            console.error('【MinIO上传】uni.request失败:', JSON.stringify(err))
            reject(new Error('上传网络错误'))
          }
        })
      }).catch(function (err) { reject(err) })
    }).catch(function (err) { reject(err) })
  })
}

export function uploadImages(filePaths, typeDir) {
  if (typeDir === undefined) typeDir = 'Isbn'
  var tasks = []
  for (var i = 0; i < filePaths.length; i++) {
    tasks.push(uploadImage(filePaths[i], typeDir))
  }
  return Promise.all(tasks)
}

export default { uploadImage, uploadImages }
