local H = wesnoth.require "lua/helper.lua"
local AH = wesnoth.require "ai/lua/ai_helper.lua"
local LS = wesnoth.require "lua/location_set.lua"

local function get_dog(cfg)
    local dogs = AH.get_units_with_moves {
        side = wesnoth.current.side,
        { "and", cfg.filter },
        { "not", { { "filter_adjacent", { side = wesnoth.current.side, { "and", cfg.filter_second } } } } }
    }
    return dogs[1]
end

local ca_herding_dog_move = {}

function ca_herding_dog_move:evaluation(ai, cfg)
    -- As a final step, any dog not adjacent to a sheep moves within herding_perimeter
    if get_dog(cfg) then return cfg.ca_score end
    return 0
end

function ca_herding_dog_move:execution(ai, cfg)
    -- We simply move the first dog first, order does not matter
    local dog = get_dog(cfg)
    local herding_perimeter = LS.of_pairs(wesnoth.get_locations(cfg.filter_location))

    -- Find average distance of herding_perimeter from center
    local av_dist = 0
    herding_perimeter:iter( function(x, y, v)
        av_dist = av_dist + H.distance_between(x, y, cfg.herd_x, cfg.herd_y)
    end)
    av_dist = av_dist / herding_perimeter:size()

    local best_hex = AH.find_best_move(dog, function(x, y)
        -- Prefer hexes on herding_perimeter, or close to it
        -- Or, if dog cannot get there, prefer to be av_dist from the center
        local rating = 0
        if herding_perimeter:get(x, y) then
            rating = rating + 1000 + math.random(99) / 100.
        else
            rating = rating
                - math.abs(H.distance_between(x, y, cfg.herd_x, cfg.herd_y) - av_dist)
                + math.random(99) / 100.
        end

        return rating
    end)

    AH.movefull_stopunit(ai, dog, best_hex)
end

return ca_herding_dog_move
