-- Copyright (C) 2017 yushi studio <ywb94@qq.com> github.com/ywb94
-- Licensed to the public under the GNU General Public License v3.
local m, s, o, kcp_enable
local vssr = 'vssr'
local uci = luci.model.uci.cursor()

local fs = require 'nixio.fs'
local sys = require 'luci.sys'
local sid = arg[1]
local uuid = luci.sys.exec('cat /proc/sys/kernel/random/uuid')

local function isKcptun(file)
    if not fs.access(file, 'rwx', 'rx', 'rx') then
        fs.chmod(file, 755)
    end

    local str = sys.exec(file .. " -v | awk '{printf $1}'")
    return (str:lower() == 'kcptun')
end

local server_table = {}
local encrypt_methods = {
    'none',
    'table',
    'rc4',
    'rc4-md5-6',
    'rc4-md5',
    'aes-128-cfb',
    'aes-192-cfb',
    'aes-256-cfb',
    'aes-128-ctr',
    'aes-192-ctr',
    'aes-256-ctr',
    'bf-cfb',
    'camellia-128-cfb',
    'camellia-192-cfb',
    'camellia-256-cfb',
    'cast5-cfb',
    'des-cfb',
    'idea-cfb',
    'rc2-cfb',
    'seed-cfb',
    'salsa20',
    'chacha20',
    'chacha20-ietf'
}

local encrypt_methods_ss = {
    -- aead
    'aes-128-gcm',
    'aes-192-gcm',
    'aes-256-gcm',
    'chacha20-ietf-poly1305',
    'xchacha20-ietf-poly1305', -- stream
    'table',
    'rc4',
    'rc4-md5',
    'aes-128-cfb',
    'aes-192-cfb',
    'aes-256-cfb',
    'aes-128-ctr',
    'aes-192-ctr',
    'aes-256-ctr',
    'bf-cfb',
    'camellia-128-cfb',
    'camellia-192-cfb',
    'camellia-256-cfb',
    'salsa20',
    'chacha20',
    'chacha20-ietf'
}

local protocol = {
    'origin',
    'verify_deflate',
    'auth_sha1_v4',
    'auth_aes128_sha1',
    'auth_aes128_md5',
    'auth_chain_a',
    'auth_chain_b',
    'auth_chain_c',
    'auth_chain_d',
    'auth_chain_e',
    'auth_chain_f'
}

obfs = {
    'plain',
    'http_simple',
    'http_post',
    'random_head',
    'tls1.2_ticket_auth'
}
local securitys = {
    'auto',
    'none',
    'aes-128-gcm',
    'chacha20-poly1305'
}

local flows = {
    'xtls-rprx-origin',
    'xtls-rprx-origin-udp443',
    'xtls-rprx-direct',
    'xtls-rprx-direct-udp443',
    'xtls-rprx-splice',
    'xtls-rprx-splice-udp443'
}

m = Map(vssr, translate('Edit vssr Server'))
m.redirect = luci.dispatcher.build_url('admin/services/vssr/servers')
if m.uci:get(vssr, sid) ~= 'servers' then
    luci.http.redirect(m.redirect)
    return
end

-- [[ Servers Setting ]]--
s = m:section(NamedSection, sid, 'servers')
s.anonymous = true
s.addremove = false

o = s:option(DummyValue, 'ssr_url', translate('Configuration Url'))
o.rawhtml = true
o.template = 'vssr/ssrurl'
o.value = sid

o = s:option(ListValue, 'type', translate('Server Node Type'))
o:value('ssr', translate('ShadowsocksR'))
if nixio.fs.access('/usr/bin/ss-redir') then
    o:value('ss', translate('Shadowsocks New Version'))
end

if nixio.fs.access('/usr/bin/xray') then
    o:value('v2ray', translate('V2Ray'))
    o:value('vless', translate('VLESS'))
end

if nixio.fs.access('/usr/sbin/trojan') then
    o:value('trojan', translate('Trojan'))
end

if nixio.fs.access('/usr/bin/hysteria') then
    o:value('hysteria', translate('Hysteria'))
end

o.description = translate('Using incorrect encryption mothod may causes service fail to start')

o = s:option(Value, 'alias', translate('Alias(optional)'))

o = s:option(Value, 'flag', translate('Area'))
o.description = translate('请自己指定。格式：cn us hk 等')
o.rmempty = true

o = s:option(Value, 'server', translate('Server Address'))
o.datatype = 'host'
o.rmempty = false

o = s:option(Value, 'server_port', translate('Server Port'))
o.datatype = 'port'
o.rmempty = false

o = s:option(Value, 'password', translate('Password'))
o.password = true
o.rmempty = true
o:depends('type', 'ssr')
o:depends('type', 'ss')
o:depends('type', 'trojan')

o = s:option(Value, 'peer', translate('Peer'))
o.datatype = 'host'
o.rmempty = true
o:depends('type', 'trojan')

o = s:option(ListValue, 'encrypt_method', translate('Encrypt Method'))
for _, v in ipairs(encrypt_methods) do
    o:value(v)
end
o.rmempty = true
o:depends('type', 'ssr')

o = s:option(ListValue, 'encrypt_method_ss', translate('Encrypt Method'))
for _, v in ipairs(encrypt_methods_ss) do
    o:value(v)
end
o.rmempty = true
o:depends('type', 'ss')

-- o:depends("type", "hysteria")
o = s:option(Value, 'h_obfs', translate('Hysteria Obfs'))
o.datatype = "minlength(1)"
o.rmempty = false
o:depends('type', 'hysteria')

-- 协议
o = s:option(ListValue, 'h_protocol', translate('Protocol'))
o:value('udp', 'UDP')
o:value('wechat-video', 'Wechat Video')
o:value('faketcp', 'Fake TCP')
o.rmempty = false
o:depends('type', 'hysteria')

-- up_mbps
o = s:option(Value, 'h_up_mbps', translate('Up Mbps'))
o.datatype = "uinteger"
o.rmempty = false
o:depends('type', 'hysteria')

-- down_mbps
o = s:option(Value, 'h_down_mbps', translate('Down Mbps'))
o.datatype = "uinteger"
o.rmempty = false
o:depends('type', 'hysteria')

o = s:option(Value, 'h_server_name', translate('Server Name'))
o.datatype = 'host'
o.rmempty = true
o:depends('type', 'hysteria')

-- Shadowsocks Plugin
o = s:option(Value, 'plugin', translate('Plugin'))
o.rmempty = true
o:depends('type', 'ss')

o = s:option(Value, 'plugin_opts', translate('Plugin Opts'))
o.rmempty = true
o:depends('type', 'ss')

o = s:option(ListValue, 'protocol', translate('Protocol'))
for _, v in ipairs(protocol) do
    o:value(v)
end
o.rmempty = true
o:depends('type', 'ssr')

o = s:option(Value, 'protocol_param', translate('Protocol param(optional)'))
o:depends('type', 'ssr')

o = s:option(ListValue, 'obfs', translate('Obfs'))
for _, v in ipairs(obfs) do
    o:value(v)
end
o.rmempty = true
o:depends('type', 'ssr')

o = s:option(Value, 'obfs_param', translate('Obfs param(optional)'))
o:depends('type', 'ssr')

-- AlterId
o = s:option(Value, 'alter_id', translate('AlterId'))
o.datatype = 'port'
o.default = 16
o.rmempty = true
o:depends('type', 'v2ray')

-- VmessId
o = s:option(Value, 'vmess_id', translate('VMESS/VLESS ID (UUID)'))
o.rmempty = true
o.default = uuid
o:depends('type', 'v2ray')
o:depends('type', 'vless')
o:depends('type', 'xray')

-- VLESS 加密方式
o = s:option(Value, 'vless_encryption', translate('VLESS Encryption'))
o.rmempty = true
o.default = 'none'
o:depends('type', 'vless')
o:depends('type', 'xray')

-- 加密方式
o = s:option(ListValue, 'security', translate('Encrypt Method'))
for _, v in ipairs(securitys) do
    o:value(v, v:upper())
end
o.rmempty = true
o:depends('type', 'v2ray')

-- 传输协议
o = s:option(ListValue, 'transport', translate('Transport'))
o:value('tcp', 'TCP')
o:value('kcp', 'mKCP')
o:value('ws', 'WebSocket')
o:value('h2', 'HTTP/2')
o:value('quic', 'QUIC')
o.rmempty = true
o:depends('type', 'v2ray')
o:depends('type', 'vless')
o:depends('type', 'xray')

-- [[ TCP部分 ]]--

-- TCP伪装
o = s:option(ListValue, 'tcp_guise', translate('Camouflage Type'))
o:depends('transport', 'tcp')
o:value('none', translate('None'))
o:value('http', 'HTTP')
o.rmempty = true

-- HTTP域名
o = s:option(DynamicList, 'http_host', translate('HTTP Host'))
o:depends('tcp_guise', 'http')
o.rmempty = true

-- HTTP路径
o = s:option(DynamicList, 'http_path', translate('HTTP Path'))
o:depends('tcp_guise', 'http')
o.rmempty = true

-- [[ WS部分 ]]--

-- WS域名
o = s:option(Value, 'ws_host', translate('WebSocket Host'))
o:depends('transport', 'ws')
o.rmempty = true

-- WS路径
o = s:option(Value, 'ws_path', translate('WebSocket Path'))
o:depends('transport', 'ws')
o.rmempty = true

-- [[ H2部分 ]]--

-- H2域名
o = s:option(DynamicList, 'h2_host', translate('HTTP/2 Host'))
o:depends('transport', 'h2')
o.rmempty = true

-- H2路径
o = s:option(Value, 'h2_path', translate('HTTP/2 Path'))
o:depends('transport', 'h2')
o.rmempty = true

-- [[ QUIC部分 ]]--

o = s:option(ListValue, 'quic_security', translate('QUIC Security'))
o:depends('transport', 'quic')
o.rmempty = true
o:value('none', translate('None'))
o:value('aes-128-gcm', translate('aes-128-gcm'))
o:value('chacha20-poly1305', translate('chacha20-poly1305'))

o = s:option(Value, 'quic_key', translate('QUIC Key'))
o:depends('transport', 'quic')
o.rmempty = true

o = s:option(ListValue, 'quic_guise', translate('Header'))
o:depends('transport', 'quic')
o.rmempty = true
o:value('none', translate('None'))
o:value('srtp', translate('VideoCall (SRTP)'))
o:value('utp', translate('BitTorrent (uTP)'))
o:value('wechat-video', translate('WechatVideo'))
o:value('dtls', 'DTLS 1.2')
o:value('wireguard', 'WireGuard')
-- [[ mKCP部分 ]]--

o = s:option(ListValue, 'kcp_guise', translate('Camouflage Type'))
o:depends('transport', 'kcp')
o:value('none', translate('None'))
o:value('srtp', translate('VideoCall (SRTP)'))
o:value('utp', translate('BitTorrent (uTP)'))
o:value('wechat-video', translate('WechatVideo'))
o:value('dtls', 'DTLS 1.2')
o:value('wireguard', 'WireGuard')
o.rmempty = true

o = s:option(Value, 'mtu', translate('MTU'))
o.datatype = 'uinteger'
o:depends('transport', 'kcp')
o.default = 1350
o.rmempty = true

o = s:option(Value, 'tti', translate('TTI'))
o.datatype = 'uinteger'
o:depends('transport', 'kcp')
o.default = 50
o.rmempty = true

o = s:option(Value, 'uplink_capacity', translate('Uplink Capacity'))
o.datatype = 'uinteger'
o:depends('transport', 'kcp')
o.default = 5
o.rmempty = true

o = s:option(Value, 'downlink_capacity', translate('Downlink Capacity'))
o.datatype = 'uinteger'
o:depends('transport', 'kcp')
o.default = 20
o.rmempty = true

o = s:option(Value, 'read_buffer_size', translate('Read Buffer Size'))
o.datatype = 'uinteger'
o:depends('transport', 'kcp')
o.default = 2
o.rmempty = true

o = s:option(Value, 'write_buffer_size', translate('Write Buffer Size'))
o.datatype = 'uinteger'
o:depends('transport', 'kcp')
o.default = 2
o.rmempty = true

o = s:option(Value, 'seed', translate('Seed'))
o:depends('transport', 'kcp')
o.default = ''
o.rmempty = true

o = s:option(Flag, 'congestion', translate('Congestion'))
o:depends('transport', 'kcp')
o.rmempty = true

-- [[ allowInsecure ]]--
o = s:option(Flag, 'insecure', translate('allowInsecure'))
o.rmempty = false
o:depends('type', 'v2ray')
o:depends('type', 'trojan')
o:depends('type', 'vless')
o:depends('type', 'xray')
o:depends('type', 'hysteria')

-- [[ TLS ]]--
o = s:option(Flag, 'tls', translate('TLS'))
o.rmempty = true
o.default = '0'
o:depends('type', 'v2ray')
o:depends('type', 'vless')
o:depends('type', 'xray')

o = s:option(Value, 'tls_host', translate('TLS Host'))
--o:depends("type", "trojan")
o:depends('tls', '1')
o.rmempty = true

-- XTLS
o = s:option(Flag, 'xtls', translate('XTLS'))
o.rmempty = true
o.default = '0'
o:depends({type = 'vless', tls = '1'})
o:depends({type = 'xray', tls = '1'})

-- Flow
o = s:option(ListValue, 'vless_flow', translate('Flow'))
for _, v in ipairs(flows) do
    o:value(v, v)
end
o.rmempty = true
o.default = 'xtls-rprx-splice'
o:depends('xtls', '1')

-- [[ Mux ]]--
o = s:option(Flag, 'mux', translate('Mux'))
o.rmempty = true
o.default = '0'
o:depends('type', 'v2ray')
o:depends('type', 'vless')

o = s:option(Value, 'concurrency', translate('Concurrency'))
o.datatype = 'uinteger'
o.rmempty = true
o.default = '8'
o:depends('mux', '1')

-- [[NO self cert]]

o = s:option(Flag, 'fast_open', translate('TCP Fast Open'))
o.rmempty = true
o.default = '0'
o:depends('type', 'ssr')
o:depends('type', 'ss')
o:depends('type', 'trojan')

o = s:option(Flag, 'switch_enable', translate('Enable Auto Switch'))
o.rmempty = false
o.default = '1'

o = s:option(Value, 'local_port', translate('Local Port'))
o.datatype = 'port'
o.default = 1234
o.rmempty = false

if nixio.fs.access('/usr/bin/kcptun-client') then
    kcp_enable = s:option(Flag, 'kcp_enable', translate('KcpTun Enable'), translate('bin:/usr/bin/kcptun-client'))
    kcp_enable.rmempty = true
    kcp_enable.default = '0'
    kcp_enable:depends('type', 'ssr')
    kcp_enable:depends('type', 'ss')

    o = s:option(Value, 'kcp_port', translate('KcpTun Port'))
    o.datatype = 'port'
    o.default = 4000
    function o.validate(self, value, section)
        local kcp_file = '/usr/bin/kcptun-client'
        local enable = kcp_enable:formvalue(section) or kcp_enable.disabled
        if enable == kcp_enable.enabled then
            if not fs.access(kcp_file) then
                return nil, translate("Haven't a Kcptun executable file")
            elseif not isKcptun(kcp_file) then
                return nil, translate('Not a Kcptun executable file')
            end
        end

        return value
    end
    o:depends('type', 'ssr')
    o:depends('type', 'ss')

    o = s:option(Value, 'kcp_password', translate('KcpTun Password'))
    o.password = true
    o:depends('type', 'ssr')
    o:depends('type', 'ss')

    o = s:option(Value, 'kcp_param', translate('KcpTun Param'))
    o.default = '--nocomp'
    o:depends('type', 'ssr')
    o:depends('type', 'ss')
end

return m
