// Data list 
local me = LocalPlayer()

local data = {
    [ "rust_ore" ] = {
        priority = 2000,
        tool = 1,
    },
    [ "prop_dynamic" ] = {
        priority = 1000,
        tool = 2,
        
        check = function( ent )
            return ent:IsTree()
        end
    },
}

// Tools data
local tools = { ready = false, allowed = { [3] = false, [2] = false, [1] = false }, list = {} }
tools.class = { ["rust_rock"] = { m = 3, p = 1 }, ["rust_stonehatchet"] = { m = 2, p = 1 }, ["rust_hatchet"] = { m = 2, p = 2 }, ["rust_stonepickaxe"] = { m = 1, p = 1 }, ["rust_pickaxe"] = { m = 1, p = 2 } }

function tools.Update()
    local weps = me:GetWeapons()

    tools.ready = false 
    tools.list = {}
    
    for i = 1, 3 do
        tools.allowed[ i ] = false
        tools.list[ i ] = {}
    end

    for i = 1, #weps do
        local wep = weps[ i ]

        local class = wep:GetClass() 

        if not tools.class[ class ] then
            continue 
        end

        local mode = tools.class[ class ].m
        tools.allowed[ mode ] = true 

        table.insert( tools.list[ mode ], { ent = wep, class = class, mode = mode } )

        if not tools.ready then
            tools.ready = true 
        end
    end
end

local sortingmethod = function( a, b ) return a.p > b.p end
local selected = -1
function tools.Select( mode )
    if selected == mode or selected == 3 then
        return true 
    end

    local wlist = tools.list[ mode ]

    if #wlist == 0 then
        if #tools.list[ 3 ] > 0 then
            input.SelectWeapon( tools.list[ 3 ][ 1 ].ent )
            selected = 3

            return true
        end

        selected = -1
        return false 
    end

    table.sort( wlist, sortingmethod )
    input.SelectWeapon( wlist[ 1 ].ent )
    selected = mode 

    return true
end

// Entity listing 
local entz = {}

local sortEntz = function( a, b )
    return a.dist < b.dist and ( a.priority > b.priority or a.priority == b.priority )
end

local maxDistance = 4096 * 4096 
local function UpdateEntities()
    local entities = ents.GetAll() 
    local mypos = me:GetPos()

    entz = {}

    for i = 1, #entities do
        local ent = entities[ i ]

        local class = ent:GetClass()
        if not data[ class ] then
            continue 
        end
        
        local cdata = data[ class ]
        if cdata.check and not cdata.check( ent ) then
            continue 
        end

        if #tools.list[ cdata.tool ] == 0 and #tools.list[ 3 ] == 0 then
            continue 
        end

        local pos = ent:GetPos()
        local dist = pos:DistToSqr( mypos )

        if dist > maxDistance then
            continue 
        end

        entz[ #entz + 1 ] = {
            ent = ent,
            dist = dist,
            pos = pos,
            mode = cdata.tool,
            priority = cdata.priority
        } 
    end

    table.sort( entz, sortEntz )

    return entz
end

// Simple path-finder 
local path = {}

local trResults = {}
local trStruct = {}

local function FindPathToNearestEntity()
    local tar = entz[ 1 ]
 
    if not IsValid( tar.ent ) then
        table.remove( entz, 1 )
        return 
    end

    return tar, tools.Select( tar.mode )
end

// Setup shit 
tools.Update()
UpdateEntities()

local lastupd = 0 
local function CreateMove( cmd )
    local cmdnum = cmd:CommandNumber()

    if cmdnum == 0 or not me:Alive() or not input.IsKeyDown( KEY_V ) then
        return 
    end

    local wep = me:GetActiveWeapon()

    if not IsValid( wep ) then
        return 
    end

    tools.Update()

    local time = CurTime()
    if time > lastupd then
        UpdateEntities()

        lastupd = time + 8
    end

    local tbl, canwork = FindPathToNearestEntity()

    if not tbl then
        return 
    end

    local ent = tbl.ent 

    if not canwork or not IsValid( ent ) or not wep.Range then
        return 
    end
    
    local isOre = tbl.mode == 1

    local eyePos = me:EyePos()
    local entPos = isOre and ent:GetWeakSpot() or ent:GetPos()

    local aimAng = ( entPos - eyePos ):Angle()
    aimAng.r = 0 
    
    if not isOre then 
        aimAng.p = 0 
    end

    aimAng:Normalize()

    cmd:SetViewAngles( aimAng )

    cmd:SetSideMove( 0 )
    cmd:SetForwardMove( 10000 )
    cmd:AddKey( IN_SPEED )

    trResults = wep:TraceRange( wep.Range )

    if trResults.Hit and trResults.Entity == ent then
        print( wep:GetNextAttack() )

        cmd:ClearButtons()

        if cmdnum % 2 == 0 then
            cmd:AddKey( IN_ATTACK )
        end
    end
end

hook.Add( "CreateMove", "grust.Automation", CreateMove )