-- Rush Duel 代价
RushDuel = RushDuel or {}

-- 内部方法: 选择匹配卡片, 执行操作
function RushDuel._private_cost_select_match(hint, filter, s_range, o_range, min, max, except_self, action)
    return function(e, tp, eg, ep, ev, re, r, rp, chk)
        local expect = nil
        if except_self then
            expect = e:GetHandler()
        end
        if chk == 0 then
            return Duel.IsExistingMatchingCard(filter, tp, s_range, o_range, min, expect, e, tp, eg, ep, ev, re, r, rp)
        end
        Duel.Hint(HINT_SELECTMSG, tp, hint)
        local g = Duel.SelectMatchingCard(tp, filter, tp, s_range, o_range, min, max, expect, e, tp, eg, ep, ev, re, r, rp)
        action(g, e, tp, eg, ep, ev, re, r, rp)
    end
end
-- 内部方法: 选择子卡片组, 执行操作
function RushDuel._private_cost_select_group(hint, filter, check, s_range, o_range, min, max, except_self, action)
    return function(e, tp, eg, ep, ev, re, r, rp, chk)
        local expect = nil
        if except_self then
            expect = e:GetHandler()
        end
        local g = Duel.GetMatchingGroup(filter, tp, s_range, o_range, expect, e, tp, eg, ep, ev, re, r, rp)
        if chk == 0 then
            return g:CheckSubGroup(check, min, max, e, tp, eg, ep, ev, re, r, rp)
        end
        Duel.Hint(HINT_SELECTMSG, tp, hint)
        local sg = g:SelectSubGroup(tp, check, false, min, max, e, tp, eg, ep, ev, re, r, rp)
        action(sg, e, tp, eg, ep, ev, re, r, rp)
    end
end
-- 内部方法: 送去墓地动作
function RushDuel._private_action_send_grave(reason, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return function(g, e, tp, eg, ep, ev, re, r, rp)
        RushDuel.HintOrConfirm(g, hint_selection, confirm, 1 - tp)
        RushDuel.SetLabelAndObject(e, g, set_label_before, set_object_before)
        if Duel.SendtoGrave(g, reason) ~= 0 and (set_label_after ~= nil or set_object_after ~= nil) then
            local og = Duel.GetOperatedGroup()
            RushDuel.SetLabelAndObject(e, og, set_label_after, set_object_after)
        end
    end
end
-- 内部方法: 返回卡组动作
function RushDuel._private_action_send_deck_sort(sequence, reason, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return function(g, e, tp, eg, ep, ev, re, r, rp)
        RushDuel.HintOrConfirm(g, hint_selection, confirm, 1 - tp)
        RushDuel.SetLabelAndObject(e, g, set_label_before, set_object_before)
        local og, ct = RushDuel.SendToDeckSort(g, sequence, reason, tp, tp)
        RushDuel.SetLabelAndObject(e, og, set_label_after, set_object_after)
    end
end
-- 内部方法: 返回卡组上面或下面动作
function RushDuel._private_action_send_deck_top_or_bottom(top_desc, bottom_desc, reason, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return function(g, e, tp, eg, ep, ev, re, r, rp)
        RushDuel.HintOrConfirm(g, hint_selection, confirm, 1 - tp)
        RushDuel.SetLabelAndObject(e, g, set_label_before, set_object_before)
        local sequence = Duel.SelectOption(tp, top_desc, bottom_desc)
        local og, ct = RushDuel.SendToDeckSort(g, sequence, reason, tp, tp)
        RushDuel.SetLabelAndObject(e, og, set_label_after, set_object_after)
    end
end
-- 内部方法: 返回手卡动作
function RushDuel._private_action_send_hand(reason, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return function(g, e, tp, eg, ep, ev, re, r, rp)
        if hint_selection then
            Duel.HintSelection(g)
        end
        RushDuel.SetLabelAndObject(e, g, set_label_before, set_object_before)
        if Duel.SendtoHand(g, nil, reason) ~= 0 then
            local og = Duel.GetOperatedGroup()
            if confirm then
                Duel.ConfirmCards(1 - tp, og)
            end
            RushDuel.SetLabelAndObject(e, og, set_label_after, set_object_after)
        end
    end
end

-- 代价: 选择匹配卡片, 送去墓地
function RushDuel.CostSendMatchToGrave(filter, field, min, max, except_self, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    local action = RushDuel._private_action_send_grave(REASON_COST, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel._private_cost_select_match(HINTMSG_TOGRAVE, filter, field, 0, min, max, except_self, action)
end
-- 代价: 选择子卡片组, 送去墓地
function RushDuel.CostSendGroupToGrave(filter, check, field, min, max, except_self, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    local action = RushDuel._private_action_send_grave(REASON_COST, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel._private_cost_select_group(HINTMSG_TOGRAVE, filter, check, field, 0, min, max, except_self, action)
end
-- 代价: 选择匹配卡片, 返回卡组 (排序)
function RushDuel.CostSendMatchToDeckSort(filter, field, min, max, except_self, sequence, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    local action = RushDuel._private_action_send_deck_sort(sequence, REASON_COST, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel._private_cost_select_match(HINTMSG_TODECK, filter, field, 0, min, max, except_self, action)
end
-- 代价: 选择子卡片组, 返回卡组 (排序)
function RushDuel.CostSendGroupToDeckSort(filter, check, field, min, max, except_self, sequence, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    local action = RushDuel._private_action_send_deck_sort(sequence, REASON_COST, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel._private_cost_select_group(HINTMSG_TODECK, filter, check, field, 0, min, max, except_self, action)
end
-- 代价: 选择匹配卡片, 返回卡组上面或下面
function RushDuel.CostSendMatchToDeckTopOrBottom(filter, field, min, max, except_self, top_desc, bottom_desc, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    local action = RushDuel._private_action_send_deck_top_or_bottom(top_desc, bottom_desc, REASON_COST, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel._private_cost_select_match(HINTMSG_TODECK, filter, field, 0, min, max, except_self, action)
end
-- 代价: 选择子卡片组, 返回卡组上面或下面
function RushDuel.CostSendGroupToDeckTopOrBottom(filter, check, field, min, max, except_self, top_desc, bottom_desc, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    local action = RushDuel._private_action_send_deck_top_or_bottom(top_desc, bottom_desc, REASON_COST, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel._private_cost_select_group(HINTMSG_TODECK, filter, check, field, 0, min, max, except_self, action)
end
-- 代价: 选择匹配卡片, 返回手卡
function RushDuel.CostSendMatchToHand(filter, field, min, max, except_self, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    local action = RushDuel._private_action_send_hand(REASON_COST, hint_selection, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel._private_cost_select_match(HINTMSG_TOGRAVE, filter, field, 0, min, max, except_self, action)
end

-- 代价: 支付LP
function RushDuel.CostPayLP(lp)
    return function(e, tp, eg, ep, ev, re, r, rp, chk)
        if chk == 0 then
            return Duel.CheckLPCost(tp, lp)
        end
        Duel.PayLPCost(tp, lp)
    end
end
-- 代价: 把手卡给对方观看
function RushDuel.CostShowHand(filter, min, max, set_label, set_object)
    return RushDuel._private_cost_select_match(HINTMSG_CONFIRM, filter, LOCATION_HAND, 0, min, max, true, function(g, e, tp, eg, ep, ev, re, r, rp)
        RushDuel.SetLabelAndObject(e, g, set_label, set_object)
        Duel.ConfirmCards(1 - tp, g)
        Duel.ShuffleHand(tp)
    end)
end
-- 代价: 把手卡给对方观看 (子卡片组)
function RushDuel.CostShowGroupHand(filter, check, min, max, set_label, set_object)
    return RushDuel._private_cost_select_group(HINTMSG_CONFIRM, filter, check, LOCATION_HAND, 0, min, max, true, function(g, e, tp, eg, ep, ev, re, r, rp)
        RushDuel.SetLabelAndObject(e, g, set_label, set_object)
        Duel.ConfirmCards(1 - tp, g)
        Duel.ShuffleHand(tp)
    end)
end
-- 代价: 把额外卡组给对方观看 (子卡片组)
function RushDuel.CostShowGroupExtra(filter, check, min, max, set_label, set_object)
    return RushDuel._private_cost_select_group(HINTMSG_CONFIRM, filter, check, LOCATION_EXTRA, 0, min, max, false, function(g, e, tp, eg, ep, ev, re, r, rp)
        RushDuel.SetLabelAndObject(e, g, set_label, set_object)
        Duel.ConfirmCards(1 - tp, g)
    end)
end
-- 代价: 从卡组上面把卡送去墓地
function RushDuel.CostSendDeckTopToGrave(count, set_label, set_object)
    return function(e, tp, eg, ep, ev, re, r, rp, chk)
        if chk == 0 then
            return Duel.IsPlayerCanDiscardDeckAsCost(tp, count)
        end
        if Duel.DiscardDeck(tp, count, REASON_COST) ~= 0 and (set_label ~= nil or set_object ~= nil) then
            local og = Duel.GetOperatedGroup()
            RushDuel.SetLabelAndObject(e, og, set_label, set_object)
        end
    end
end
-- 代价: 从卡组上面把任意数量的卡送去墓地
function RushDuel.CostSendDeckTopAnyToGrave(desc, min, max, set_label, set_object)
    return function(e, tp, eg, ep, ev, re, r, rp, chk)
        if chk == 0 then
            return Duel.IsPlayerCanDiscardDeckAsCost(tp, min)
        end
        local ops = {}
        for i = min, max do
            if Duel.IsPlayerCanDiscardDeckAsCost(tp, i) then
                table.insert(ops, i)
            end
        end
        Duel.Hint(HINT_SELECTMSG, tp, desc)
        local count = Duel.AnnounceNumber(tp, table.unpack(ops))
        if Duel.DiscardDeck(tp, count, REASON_COST) ~= 0 and (set_label ~= nil or set_object ~= nil) then
            local og = Duel.GetOperatedGroup()
            RushDuel.SetLabelAndObject(e, og, set_label, set_object)
        end
    end
end
-- 代价: 从卡组下面把卡送去墓地
function RushDuel.CostSendDeckBottomToGrave(count, set_label, set_object)
    return function(e, tp, eg, ep, ev, re, r, rp, chk)
        if chk == 0 then
            return Duel.IsPlayerCanDiscardDeckAsCost(tp, count)
        end
        local dg = RushDuel.GetDeckBottomGroup(tp, count)
        Duel.DisableShuffleCheck()
        if Duel.SendtoGrave(dg, REASON_COST) ~= 0 and (set_label ~= nil or set_object ~= nil) then
            local og = Duel.GetOperatedGroup()
            RushDuel.SetLabelAndObject(e, og, set_label, set_object)
        end
    end
end
-- 代价: 把自己场上表侧表示的这张卡送去墓地
function RushDuel.CostSendSelfToGrave()
    return function(e, tp, eg, ep, ev, re, r, rp, chk)
        if chk == 0 then
            return e:GetHandler():IsAbleToGraveAsCost()
        end
        Duel.SendtoGrave(RushDuel.ToMaximunGroup(e:GetHandler()), REASON_COST)
    end
end
-- 代价: 把手卡送去墓地
function RushDuel.CostSendHandToGrave(filter, min, max, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToGrave(filter, LOCATION_HAND, min, max, true, false, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把手卡送去墓地 (子卡片组)
function RushDuel.CostSendHandSubToGrave(filter, check, min, max, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendGroupToGrave(filter, check, LOCATION_HAND, min, max, true, false, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把怪兽送去墓地
function RushDuel.CostSendMZoneToGrave(filter, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToGrave(filter, LOCATION_MZONE, min, max, except_self, false, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把怪兽送去墓地 (子卡片组)
function RushDuel.CostSendMZoneSubToGrave(filter, check, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendGroupToGrave(filter, check, LOCATION_MZONE, min, max, except_self, false, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把场上的卡送去墓地
function RushDuel.CostSendOnFieldToGrave(filter, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToGrave(filter, LOCATION_ONFIELD, min, max, except_self, false, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把场上的卡送去墓地 (子卡片组)
function RushDuel.CostSendOnFieldSubToGrave(filter, check, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendGroupToGrave(filter, check, LOCATION_ONFIELD, min, max, except_self, false, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让怪兽返回卡组
function RushDuel.CostSendMZoneToDeck(filter, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_MZONE, min, max, except_self, SEQ_DECKSHUFFLE, true, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让怪兽返回卡组下面
function RushDuel.CostSendMZoneToDeckBottom(filter, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_MZONE, min, max, except_self, SEQ_DECKBOTTOM, true, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让怪兽返回卡组上面或下面
function RushDuel.CostSendMZoneToDeckTopOrBottom(filter, min, max, top_desc, bottom_desc, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckTopOrBottom(filter, LOCATION_MZONE, min, max, except_self, top_desc, bottom_desc, true, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让场上的卡返回卡组
function RushDuel.CostSendOnFieldToDeck(filter, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_ONFIELD, min, max, except_self, SEQ_DECKSHUFFLE, true, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让场上的卡返回卡组下面
function RushDuel.CostSendOnFieldToDeckBottom(filter, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_ONFIELD, min, max, except_self, SEQ_DECKBOTTOM, true, false, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把手卡返回卡组
function RushDuel.CostSendHandToDeck(filter, min, max, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_HAND, min, max, true, SEQ_DECKSHUFFLE, false, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把手卡返回卡组上面
function RushDuel.CostSendHandToDeckTop(filter, min, max, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_HAND, min, max, true, SEQ_DECKTOP, false, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把手卡返回卡组下面
function RushDuel.CostSendHandToDeckBottom(filter, min, max, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_HAND, min, max, true, SEQ_DECKBOTTOM, false, confirm, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让墓地的卡返回卡组
function RushDuel.CostSendGraveToDeck(filter, min, max, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_GRAVE, min, max, false, SEQ_DECKSHUFFLE, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让墓地的卡返回卡组 (子卡片组)
function RushDuel.CostSendGraveSubToDeck(filter, check, min, max, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendGroupToDeckSort(filter, check, LOCATION_GRAVE, min, max, false, SEQ_DECKSHUFFLE, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让墓地的卡返回卡组上面
function RushDuel.CostSendGraveToDeckTop(filter, min, max, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_GRAVE, min, max, false, SEQ_DECKTOP, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让墓地的卡返回卡组上面 (子卡片组)
function RushDuel.CostSendGraveSubToDeckTop(filter, check, min, max, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendGroupToDeckSort(filter, check, LOCATION_GRAVE, min, max, false, SEQ_DECKTOP, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让墓地的卡返回卡组下面
function RushDuel.CostSendGraveToDeckBottom(filter, min, max, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckSort(filter, LOCATION_GRAVE, min, max, false, SEQ_DECKBOTTOM, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让墓地的卡返回卡组下面 (子卡片组)
function RushDuel.CostSendGraveSubToDeckBottom(filter, check, min, max, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendGroupToDeckSort(filter, check, LOCATION_GRAVE, min, max, false, SEQ_DECKBOTTOM, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让墓地的卡返回卡组上面或下面
function RushDuel.CostSendGraveToDeckTopOrBottom(filter, min, max, top_desc, bottom_desc, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToDeckTopOrBottom(filter, LOCATION_GRAVE, min, max, false, top_desc, bottom_desc, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 让墓地的卡返回卡组上面或下面 (子卡片组)
function RushDuel.CostSendGraveSubToDeckTopOrBottom(filter, check, min, max, top_desc, bottom_desc, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendGroupToDeckTopOrBottom(filter, check, LOCATION_GRAVE, min, max, false, top_desc, bottom_desc, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
-- 代价: 把怪兽返回手卡
function RushDuel.CostSendMZoneToHand(filter, min, max, except_self, set_label_before, set_object_before, set_label_after, set_object_after)
    return RushDuel.CostSendMatchToHand(filter, LOCATION_MZONE, min, max, except_self, false, true, set_label_before, set_object_before, set_label_after, set_object_after)
end
