local ucursor = require 'luci.model.uci'.cursor()
local name = 'vssr'
local json = require 'luci.jsonc'
local nixio = require 'nixio'
local server_section = arg[1]
local proto = arg[2]
local local_port = arg[3]
local outbounds_table = {}
local rules_table = {}

function read_conf(file)
    if not nixio.fs.access(file) then
        return nil
    end
    local rfile = io.open(file, 'r')
    local ltable = {}
    for line in rfile:lines() do
        local re = string.gsub(line, '\r', '')
        table.insert(ltable, re)
    end
    local rtable = next(ltable) ~= nil and ltable or nil
    return rtable
end

local v2ray_flow = ucursor:get_first(name, 'global', 'v2ray_flow', '0')

local custom_domain = read_conf('/etc/vssr/custom_domain.list')
local custom_ip = read_conf('/etc/vssr/custom_ip.list')

local youtube_domain = read_conf('/etc/vssr/youtube_domain.list')
local youtube_ip = read_conf('/etc/vssr/youtube_ip.list')

local tw_video_domain = read_conf('/etc/vssr/tw_video_domain.list')
local tw_video_ip = read_conf('/etc/vssr/tw_video_ip.list')

local netflix_domain = read_conf('/etc/vssr/netflix_domain.list')
local netflix_ip = read_conf('/etc/vssr/netflix_ip.list')

local disney_domain = read_conf('/etc/vssr/disney_domain.list')
local disney_ip = read_conf('/etc/vssr/disney_ip.list')

local prime_domain = read_conf('/etc/vssr/prime_domain.list')
local prime_ip = read_conf('/etc/vssr/prime_ip.list')

local tvb_domain = read_conf('/etc/vssr/tvb_domain.list')
local tvb_ip = read_conf('/etc/vssr/tvb_ip.list')

local flow_table = {
    yotube = {
        name = 'youtube',
        port = 2081,
        rules = {
            type = 'field',
            domain = youtube_domain,
            ip = youtube_ip,
            outboundTag = 'youtube'
        }
    },
    tw_video = {
        name = 'tw_video',
        port = 2082,
        rules = {
            type = 'field',
            domain = tw_video_domain,
            ip = tw_video_ip,
            outboundTag = 'tw_video'
        }
    },
    netflix = {
        name = 'netflix',
        port = 2083,
        rules = {
            type = 'field',
            domain = netflix_domain,
            ip = netflix_ip,
            outboundTag = 'netflix'
        }
    },
    disney = {
        name = 'disney',
        port = 2084,
        rules = {
            type = 'field',
            domain = disney_domain,
            ip = disney_ip,
            outboundTag = 'disney'
        }
    },
    prime = {
        name = 'prime',
        port = 2085,
        rules = {
            type = 'field',
            domain = prime_domain,
            ip = prime_ip,
            outboundTag = 'prime'
        }
    },
    tvb = {
        name = 'tvb',
        port = 2086,
        rules = {
            type = 'field',
            domain = tvb_domain,
            ip = tvb_ip,
            outboundTag = 'tvb'
        }
    },
    custom = {
        name = 'custom',
        port = 2087,
        rules = {
            type = 'field',
            domain = custom_domain,
            ip = custom_ip,
            outboundTag = 'custom'
        }
    }
}

function gen_outbound(server_node, tags, local_ports)
    local bound = {}
    if server_node == nil or server_node == 'nil' then
        bound = nil
    else
        local server = ucursor:get_all(name, server_node)
        local node_type = server.type == 'vless' and 'vless' or 'vmess'

        if server.type ~= 'v2ray' and server.type ~= 'vless' then
            bound = {
                tag = tags,
                protocol = 'socks',
                settings = {
                    servers = {
                        {address = '127.0.0.1', port = tonumber(local_ports)}
                    }
                }
            }
        else
            bound = {
                tag = tags,
                protocol = node_type,
                settings = {
                    vnext = {
                        {
                            address = server.server,
                            port = tonumber(server.server_port),
                            users = {
                                {
                                    id = server.vmess_id,
                                    alterId = server.type == 'v2ray' and tonumber(server.alter_id) or nil,
                                    security = server.type == 'v2ray' and server.security or nil,
                                    flow = (server.xtls == '1') and (server.vless_flow and server.vless_flow or 'xtls-rprx-origin') or nil,
                                    encryption = server.type == 'vless' and server.vless_encryption or nil
                                }
                            }
                        }
                    }
                },
                -- 底层传输配置
                streamSettings = {
                    network = server.transport,
                    security = (server.tls == '1') and ((server.xtls == '1') and 'xtls' or 'tls') or 'none',
                    tlsSettings = (server.tls == '1' and server.xtls ~= '1') and {allowInsecure = (server.insecure ~= '0') and true or false, serverName = server.tls_host} or nil,
                    xtlsSettings = (server.xtls == '1') and {allowInsecure = (server.insecure ~= '0') and true or false, serverName = server.tls_host} or nil,
                    kcpSettings = (server.transport == 'kcp') and
                        {
                            mtu = tonumber(server.mtu),
                            tti = tonumber(server.tti),
                            uplinkCapacity = tonumber(server.uplink_capacity),
                            downlinkCapacity = tonumber(server.downlink_capacity),
                            congestion = (server.congestion == '1') and true or false,
                            readBufferSize = tonumber(server.read_buffer_size),
                            writeBufferSize = tonumber(server.write_buffer_size),
                            header = {type = server.kcp_guise}
                        } or
                        nil,
                    wsSettings = (server.transport == 'ws') and (server.ws_path ~= nil or server.ws_host ~= nil) and
                        {
                            path = server.ws_path,
                            headers = (server.ws_host ~= nil) and {Host = server.ws_host} or nil
                        } or
                        nil,
                    httpSettings = (server.transport == 'h2') and {path = server.h2_path, host = server.h2_host} or nil,
                    quicSettings = (server.transport == 'quic') and
                        {
                            security = server.quic_security,
                            key = server.quic_key,
                            header = {type = server.quic_guise}
                        } or
                        nil
                },
                mux = {
                    enabled = (server.mux == '1') and true or false,
                    concurrency = tonumber(server.concurrency)
                }
            }
        end
    end
    return bound
end

if v2ray_flow == '1' then
    table.insert(outbounds_table, gen_outbound(server_section, 'global', 2080))
    for _, v in pairs(flow_table) do
        if (v.rules.domain ~= nil or v.rules.ip ~= nil) then
            local server = ucursor:get_first(name, 'global', v.name .. '_server')
            table.insert(outbounds_table, gen_outbound(server, v.name, v.port))

            if (v.rules.domain ~= nil) then
                domain_rules = {
                    type = 'field',
                    domain = v.rules.domain,
                    outboundTag = v.rules.outboundTag
                }
                table.insert(rules_table, (server ~= nil and server ~= 'nil') and domain_rules or nil)
            end

            if (v.rules.ip ~= nil) then
                ip_rules = {
                    type = 'field',
                    ip = v.rules.ip,
                    outboundTag = v.rules.outboundTag
                }
                table.insert(rules_table, (server ~= nil and server ~= 'nil') and ip_rules or nil)
            end
        end
    end
else
    table.insert(outbounds_table, gen_outbound(server_section, 'main', local_port))
end

local v2ray = {
    log = {
        -- error = "/var/vssrsss.log",
        -- access = "/var/v2rays.log",
        loglevel = 'warning'
    },
    -- 传入连接
    inbounds = {
        {
            port = tonumber(local_port),
            protocol = 'dokodemo-door',
            settings = {network = proto, followRedirect = true},
            sniffing = {enabled = true, destOverride = {'http', 'tls'}},
            streamSettings = {
                sockopt = {tproxy = (proto == 'tcp') and 'redirect' or 'tproxy'}
            }
        }
    },
    -- 传出连接
    outbounds = outbounds_table,
    routing = {domainStrategy = 'IPIfNonMatch', rules = rules_table}
}
print(json.stringify(v2ray, 1))
