const filenameUtil = require('scripts/filenameUtil')

String.prototype.strictTrim = function () {
  let trimed = this.trim()
  if ((matcher = trimed.match(/([\s\S]+),$/)) !== null) {
    return matcher[1]
  }
  return trimed
}

function urlsafeBase64Encode(url) {
  return $text.base64Encode(url).replace(/\-/g, '+').replace(/\\/g, '_').replace(/=+$/, '')
}

function urlsafeBase64Decode(base64) {
  // Add removed at end '='
  base64 += Array(5 - base64.length % 4).join('=');
  base64 = base64
    .replace(/\-/g, '+') // Convert '-' to '+'
    .replace(/\_/g, '/'); // Convert '_' to '/'
  return $text.base64Decode(base64).replace(/\u0000/, '');
}

function promiseConf(url) {
  return new Promise((resolve, reject) => {
    $http.get({
      url: url,
      header: {
        'User-Agent': 'Surge/1174 CFNetwork/962 Darwin/18.0.0'
      },
      handler: function (resp) {
        let data = resp.data + ''
        let filename = url
        try {
          let matcher = resp.response.runtimeValue().invoke('allHeaderFields').rawValue()["Content-Disposition"].match(/filename="?(.*?)(?:.conf|"|$)/)
          filename = matcher[1]
        } catch (e) {
          filename = filenameUtil.getConfName(url)
        }
        // 兼容不规范ssr链接
        let noPaddingData = data
        let padding = noPaddingData.length % 4 == 0 ? 0 : 4 - noPaddingData.length % 4
        for (let i = 0; i < padding; i++) {
          noPaddingData += '='
        }
        let decodedData = $text.base64Decode(data) || $text.base64Decode(noPaddingData)
        if (/\[Proxy\]([\s\S]*?)\[Proxy Group\]/.test(data)) {
          // Surge托管
          resolve({
            servers: RegExp.$1,
            filename: filename,
            type: 0
          })
        } else if (/^(ssr|ss|vmess):\/\//.test(decodedData)) {
          let rawLinks = decodedData.split(/[\n\r\|\s]+/g).filter(i => i !== '' && /^(ssr|ss|vmess):\/\//.test(i));
          let output = rawLinks.map(i => {
            if (/^ssr:\/\//.test(i)) {
              let res = decodeSSR([i])
              return res.servers
            } else if (/^ss:\/\//.test(i)) {
              let res = decodeScheme([i])
              return res.servers
            } else {
              let res = decodeVmess([i])
              return res.servers
            }
          })
          resolve({
            servers: output.reduce((p, c) => {
              return p.concat(c)
            }, []).join('\n'),
            filename: getDomain(url),
            type: 4
          })
        } else if (/^ssr:\/\//.test(decodedData)) {
          // SSR订阅
          let rawLinks = decodedData.split(/[\n\r\|\s]+/g).filter(i => i !== '' && /^ssr:\/\//.test(i));
          let res = decodeSSR(rawLinks);
          resolve({
            servers: res.servers.join('\n'),
            filename: res.sstag || filename,
            type: 1
          })
        } else if (/^ss:\/\//.test(decodedData)) {
          // SS订阅
          let rawLinks = decodedData.split(/[\n\r\|\s]+/g).filter(i => i !== '' && /^ss:\/\//.test(i));
          let serInfo = decodeScheme(rawLinks);
          resolve({
            servers: serInfo.servers.join('\n'),
            filename: serInfo.sstag || filename,
            type: 2
          })
        } else if (/^vmess:\/\//.test(decodedData)) {
          let rawLinks = decodedData.split(/[\n\r\|\s]+/g).filter(i => i !== '' && /^vmess:\/\//.test(i));
          console.log('rawLinks', typeof rawLinks);
          let res = decodeVmess(rawLinks);
          console.log('res', res);
          resolve({
            servers: res.servers.join('\n'),
            filename: res.sstag || filename,
            type: 3
          })
        } else {
          resolve()
        }
      }
    })
  })
}

function getDomain(url) {
  if (/https?:\/\/.*?\.(.*?)\.(.*?)(?=\/|$)/.test(url)) {
    return `${RegExp.$1.trim()}.${RegExp.$2.trim()}`
  }
  return '批量导入'
}

function decodeSSR(links) {
  let tag = ''
  let first = ''
  function getParam(key, content) {
    let reg = new RegExp(`${key}=(.*?)(?:&|$)`);
    let matcher = content.match(reg);
    return matcher && matcher[1] ? matcher[1] : '';
  }
  let decodedLinks = links.map(i => {
    let rawContentMatcher = i.match(/^ssr:\/\/(.*?)$/);
    if (rawContentMatcher && rawContentMatcher[1]) {
      let rawContent = urlsafeBase64Decode(rawContentMatcher[1]);
      let rawContentParts = rawContent.split(/\/*\?/g)
      let paramsMatcher = rawContentParts[0].match(/^(.*?):(.*?):(.*?):(.*?):(.*?):(.*?)$/);
      if (paramsMatcher && paramsMatcher.length === 7) {
        let host = paramsMatcher[1];
        let port = paramsMatcher[2];
        let protocol = paramsMatcher[3];
        let method = paramsMatcher[4];
        let obfs = paramsMatcher[5];
        let pass = urlsafeBase64Decode(paramsMatcher[6]);
        let obfsparam = '';
        let protoparam = '';
        let group = '';
        let remarks = '';
        if (rawContentParts.length > 1) {
          let target = rawContentParts[1];
          obfsparam = urlsafeBase64Decode(getParam('obfsparam', target));
          protoparam = urlsafeBase64Decode(getParam('protoparam', target));
          group = urlsafeBase64Decode(getParam('group', target));
          remarks = urlsafeBase64Decode(getParam('remarks', target));
        }
        if (tag === '' && group !== '') {
          tag = group;
        }
        let finalName = remarks === '' ? `${host}:${port}` : remarks
        first = finalName
        let res = `${finalName} = shadowsocksr, ${host}, ${port}, ${method}, "${pass}", protocol=${protocol}, obfs=${obfs}`;
        res += protoparam ? `, protocol_param=${protoparam}` : '';
        res += obfsparam ? `, obfs_param="${obfsparam}"` : '';
        return res;
      }
      else {
        return '';
      }
    }
    else {
      return '';
    }
  });
  let sstag = first
  if (decodedLinks.length > 1) {
    sstag = `批量SSR节点（${decodedLinks.length}）`
  }
  if (tag !== '') {
    sstag = tag
  }
  return { servers: decodedLinks, sstag: sstag }
}

function getServersFromConfFile(params) {
  let promiseArray = params.urls.map(i => promiseConf(i))
  Promise.all(promiseArray).then(confs => {
    for (let idx in confs) {
      let res = confs[idx]
      let type = res ? res.type : -1
      let filename = res ? res.filename : '';
      let servers = res ? res.servers.split(/[\n\r]+/).filter(item => item !== '').map(i => i.strictTrim()) : [];
      params.handler({ servers: servers, filename: filename, url: params.urls[idx], type: type })
    }
  }).catch(reason => {
    console.error(reason.stack)
    params.handler(null)
  })
}

function isJson(str) {
  try {
    JSON.parse(str)
  } catch (e) {
    return false
  }
  return true
}

function decodeVmess(links) {
  let result = []
  let tag = ''

  for (let idx in links) {
    let link = links[idx]

    if (/^vmess:\/\/(.*?)$/.test(link)) {
      let content = urlsafeBase64Decode(RegExp.$1)
      if (isJson(content)) {
        // v2rayN style
        let jsonConf = JSON.parse(content)
        let group = ''
        const ua = 'Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/16A5366a'
        let obfs = `,obfs=${jsonConf.net === 'ws' ? 'ws' : 'http'},obfs-path="${jsonConf.path || '/'}",obfs-header="Host:${jsonConf.host || jsonConf.add}[Rr][Nn]User-Agent:${ua}"`
        let quanVmess = `${jsonConf.ps} = vmess,${jsonConf.add},${jsonConf.port},chacha20-ietf-poly1305,"${jsonConf.id}",group=${group},over-tls=${jsonConf.tls === 'tls' ? 'true' : 'false'},certificate=1${jsonConf.type === 'none' && jsonConf.net !== 'ws' ? '' : obfs}`
        result.push(quanVmess)
      } else {
        // Quantumult style
        if (/group=(.*?),/.test(content)) {
          tag = RegExp.$1
        }
        result.push(content)
      }
    }
  }
  return { servers: result, sstag: tag || `批量V2Ray节点（${result.length}）` }
}

function decodeScheme(urls) {
  // let urls = params.ssURL
  let result = []
  let tag
  let group = ''

  for (let idx in urls) {
    let url = urls[idx]
    let method, password, hostname, port, plugin
    if (!url.includes('#')) {
      let name = '无节点名称'
      url += `#${name}`
    }
    tag = $text.URLDecode(url.match(/#(.*?)$/)[1])
    if (url.includes('?')) {
      // tag = $text.URLDecode(url.match(/#(.*?)$/)[1])
      let mdps = url.match(/ss:\/\/(.*?)@/)[1]
      let padding = 4 - mdps.length % 4
      if (padding < 4) {
        mdps += Array(padding + 1).join('=')
      }
      let userinfo = $text.base64Decode(mdps)
      method = userinfo.split(':')[0]
      password = userinfo.split(':')[1]
      let htpr = url.match(/@(.*?)\?/)[1].replace('\/', '')
      hostname = htpr.split(':')[0]
      port = htpr.split(':')[1]
      let ps = $text.URLDecode(url.match(/\?(.*?)#/)[1])
      let obfsMatcher = ps.match(/obfs=(.*?)(;|$)/)
      let obfsHostMatcher = ps.match(/obfs-host=(.*?)(&|;|$)/)
      if (obfsMatcher) {
        let obfs = obfsMatcher[1]
        let obfsHost = obfsHostMatcher ? obfsHostMatcher[1] : 'cloudfront.net'
        plugin = `obfs=${obfs}, obfs-host=${obfsHost}`
      }
      if (/group=(.*)(&|;|$)/.test(ps)) {
        group = $text.base64Decode(RegExp.$1.trim())
      }
    } else {
      if (/ss:\/\/([^#]*)/.test(url)) {
        let mdps = RegExp.$1
        if (/^(.*)@(.*?):(.*?)$/.test(mdps)) {
          hostname = RegExp.$2
          port = RegExp.$3
          let methodAndPass = urlsafeBase64Decode(RegExp.$1)
          console.log('methodAndPass', methodAndPass);
          if (/^(.*?):(.*?)$/.test(methodAndPass)) {
            method = RegExp.$1
            password = RegExp.$2
          }
        } else {
          let padding = 4 - mdps.length % 4
          if (padding < 4) {
            mdps += Array(padding + 1).join('=')
          }
          if (/^(.*?):(.*)@(.*?):(.*?)$/.test($text.base64Decode(mdps))) {
            method = RegExp.$1
            password = RegExp.$2
            hostname = RegExp.$3
            port = RegExp.$4
          }
        }
      }
    }
    let proxy = `${tag} = custom, ${hostname}, ${port}, ${method}, ${password}, https://github.com/lhie1/Rules/blob/master/SSEncrypt.module?raw=true`
    if (plugin != undefined) {
      proxy += `, ${plugin}`
    }
    result[idx] = proxy
  }
  let outName = ''
  if (group) {
    outName = group
  } else if (result.length === 1) {
    outName = tag
  } else {
    outName = `批量ss节点（${result.length}）`
  }
  return { servers: result, sstag: outName }
}

module.exports = {
  proxyFromConf: getServersFromConfFile,
  proxyFromURL: decodeScheme,
  proxyFromVmess: decodeVmess,
  proxyFromSSR: decodeSSR
}