#!/usr/bin/env lua

local json = require "luci.jsonc"
local fs   = require "nixio.fs"
local sys = require "luci.sys"
local lfs = require "lfs"

local function readfile(path)
    local s = fs.readfile(path)
    return s and (s:gsub("^%s+", ""):gsub("%s+$", ""))
end

function write_to_file(_message)
    file_logfile = io.open("/etc/ble/BLE_DATA", "a+")
    file_logfile:write(_message,"\n")
    file_logfile:flush()
    io.close(file_logfile)
end

function  fetch_data(_address, _type, _cmd_arg )
    local _cmd="gatttool -b " .. _address .. " -t " .. _type .. " --" .. _cmd_arg .. " 2>/tmp/gatt_error"
    --print(_cmd)
    --luci.sys.exec("echo %q >> /tmp/rohan" % _cmd)
    local _ret = luci.sys.exec(_cmd)
    --print(_ret)
    local size = lfs.attributes("/tmp/gatt_error", "size")
    --print(size)
    if tonumber(size) == 0 and (_ret ~= nil or _ret ~= "") then
    --      print(_cmd_arg)                                                               
            if _cmd_arg == "primary" then                                                 
                write_to_file("Primary Services :")                                       
            elseif _cmd_arg == "characteristics" then                                     
                write_to_file("Characteristics :")                                        
            end
            write_to_file(_ret)                                                           
    elseif tonumber(size) ~= 0 then
        _ret = fs.readfile("/tmp/gatt_error")
        write_to_file("Error : " .. _ret)
    else
        write_to_file("Error : " .. "Response not received. Please try again.")
    end
end

local methods = {

    isBLEConnected= {
        args = { mac = "" },
        call =function(args)
            local sys = require "luci.sys"
            local res
            local cmd 
            if args.mac then 
                cmd="ble.sh is_ble_connected " .. tostring(args.mac)
                res=luci.sys.exec(cmd)
            else
                res="Enter BT Address"
            end
            return {results = res}
        end
    },

    addMacToConfig= {
        args = { btaddress = "" , type = "" , name = ""},
        call = function(args)
            local sys = require "luci.sys"
            local res
            local cmd 
            if args.btaddress then 
                cmd="ble.sh ble_device_add " .. tostring(args.btaddress) .. " \"" .. tostring(args.type) .. " \"" .. tostring(args.name)
                --luci.sys.exec("echo %q > /tmp/rohan" % cmd)
                res=luci.sys.exec(cmd)
            else
                res="Enter BT Address"
            end
            return {results = res}
        end
    },

    getBleMacStatus={
        args = { mac = "" , type = "" , arg = "" },
        call =function(args)
            local fs = require "nixio.fs"                                                     
            local js = require "luci.jsonc"                                                   
            local sys = require "luci.sys"                                                                 
            --luci.sys.exec("echo %q >> /tmp/rohan" % args.mac)                                    
            os.remove("/etc/ble/BLE_DATA")
            os.remove("/tmp/gatt_error")
            fetch_data(args.mac, args.type, args.arg)
            return { results = fs.readfile("/etc/ble/BLE_DATA")}
        end
    },

    getBleDeviceStatus= {
        args = { type = "" },
        call = function(args)
            local sys = require "luci.sys"
            local res=nil
            if args.type then
                cmd="ble.sh ble_data " .. tostring(args.type)
                res=luci.sys.exec(cmd)
            else
                res="Enter BT Address"
            end
            return {results = res}
        end
    },

    getBleDeviceServiceHistory= {
        args = { btaddress = "", service = ""},
        call = function(args)
            local sys = require "luci.sys"
            local _service = string.gsub(tostring(args.service),' ', '\\ ')
            local res
            local cmd 
            if args.btaddress then 
                cmd="ble.sh ble_service_history_data " .. tostring(args.btaddress) .." " .. tostring(_service)
                --luci.sys.exec("echo %q > /tmp/rohan" % cmd)
                res=luci.sys.exec(cmd)
            else
                res="Enter BT Address"
            end
            return {results = res}
        end
    },

    getBleFromConfig= {
        call = function()
            local sys = require "luci.sys"
            local res=nil, maindata
            maindata=luci.sys.exec("ble.sh get_ble_devices_config")
            res=json.parse(maindata)
            return {results = res}
        end
    },

    removeBleFromconfig= {
        args = { btaddress = "", type = ""},
        call = function(args)
            local sys = require "luci.sys"
            local res
            local cmd 
            if args.btaddress then 
                cmd="ble.sh remove_ble_devices_config " .. tostring(args.btaddress) .." " .. " \"" .. tostring(args.type)  .. "\""
                --luci.sys.exec("echo %q > /tmp/rohan" % cmd)
                res=luci.sys.exec(cmd)
            else
                res="Enter BT Address"
            end
            return {results = res}
        end
    },

    connectionStatus= {
        args = { btaddress = "", mode = ""},
        call = function(args)
            local sys = require "luci.sys"
            local res=nil, maindata
            local cmd
            cmd="ble.sh connection_status " .. tostring(args.btaddress) .. " " .. tostring(args.mode)
            --luci.sys.exec("echo %q > /tmp/rohan" % cmd)
            maindata=luci.sys.exec(cmd)
            --luci.sys.exec("echo %q > /tmp/rohan123" % maindata)
            res=json.parse(maindata)
            return {results = res}
        end
    },
    connectToBLE= {
        args = { btaddress = ""},
        call = function(args)
            local sys = require "luci.sys"
            local res
            local cmd 
            if args.btaddress then 
                cmd="ble.sh connect_to_device " .. tostring(args.btaddress)
                --luci.sys.exec("echo %q > /tmp/rohan" % cmd)
                res=luci.sys.exec(cmd)
            else
                res="Enter BT Address"
            end
            return {results = res}
        end
    },
    disconnectFromBLE= {
        args = { btaddress = ""},
        call = function(args)
            local sys = require "luci.sys"
            local res
            local cmd 
            if args.btaddress then 
                cmd="ble.sh disconnect_from_device " .. tostring(args.btaddress)
                --luci.sys.exec("echo %q > /tmp/rohan" % cmd)
                res=luci.sys.exec(cmd)
            else
                res="Enter BT Address"
            end
            return {results = res}
        end
    },
    getCmdResponse= {
        args = { command="", mac = ""},
        call = function(args)
            local sys = require "luci.sys"
            local res
            local cmd 
            if args.command and args.mac then
                cmd="ble.sh getcmd_data " .. " \"" .. tostring(args.command) .. "\" "  .. tostring(args.mac)
                --luci.sys.exec("echo %q > /tmp/rohan" % cmd)
                res=luci.sys.exec(cmd)
            else
                res="Enter command"
            end
            return {results = res}
        end
    },
}


local function parseInput()
    local parse = json.new()
    local done, err

    while true do
        local chunk = io.read(4096)
        if not chunk then
            break
            elseif not done and not err then
            done, err = parse:parse(chunk)
        end
    end

    if not done then
        print(json.stringify({ error = err or "Incomplete input" }))
        os.exit(1)
    end

    return parse:get()
end


local function validateArgs(func, uargs)
    local method = methods[func]
    if not method then
        print(json.stringify({ error = "Method not found" }))
        os.exit(1)
    end

    if type(uargs) ~= "table" then
        print(json.stringify({ error = "Invalid arguments pass" }))
        os.exit(1)
    end

    uargs.ubus_rpc_session = nil
    
    local k, v
    local margs = method.args or {}
    for k, v in pairs(uargs) do
        if margs[k] == nil or
            (v ~= nil and type(v) ~= type(margs[k]))
            then
            print(json.stringify({ error = "Invalid arguments vikas" }))
            os.exit(1)
        end
    end

    return method
end

if arg[1] == "list" then
    local _, method, rv = nil, nil, {}
    for _, method in pairs(methods) do rv[_] = method.args or {} end
    print((json.stringify(rv):gsub(":%[%]", ":{}")))
    elseif arg[1] == "call" then
    local args = parseInput()
    local method = validateArgs(arg[2], args)
    local result, code = method.call(args)
    print((json.stringify(result):gsub("^%[%]$", "{}")))
    os.exit(code or 0)
end
