package com.ruoyi.generator.service.front;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
import org.springframework.stereotype.Component;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.generator.domain.front.dto.BusinessLoopPlan;
import com.ruoyi.generator.domain.front.dto.BusinessLoopPlan.BusinessLoopAction;
import com.ruoyi.generator.domain.front.dto.BusinessLoopPlan.BusinessLoopObject;
import com.ruoyi.generator.domain.front.dto.BusinessLoopPlan.BusinessLoopStateMachine;

@Component
public class BusinessLoopPlanValidator
{
    private static final int MAX_CORE_OBJECTS = 20;
    private static final int MAX_ACTIONS = 30;
    private static final Pattern ACTION_CODE = Pattern.compile("^[a-z][a-z0-9_]{1,63}$");

    public void validate(BusinessLoopPlan plan)
    {
        if (plan == null)
        {
            throw new ServiceException("Business loop plan is required");
        }
        validateCoreObjects(plan.getCoreObjects());
        validateActions(plan.getActions());
        if (countStateTransitions(plan) == 0)
        {
            throw new ServiceException("Business loop must contain at least one state transition");
        }
        if (size(plan.getQuantityRules()) == 0 && size(plan.getRecordRules()) == 0)
        {
            throw new ServiceException("Business loop must contain at least one quantity or record rule");
        }
    }

    private void validateCoreObjects(List<BusinessLoopObject> coreObjects)
    {
        if (size(coreObjects) == 0)
        {
            throw new ServiceException("Business loop core objects cannot be empty");
        }
        if (coreObjects.size() > MAX_CORE_OBJECTS)
        {
            throw new ServiceException("Business loop core object count exceeds limit");
        }
    }

    private void validateActions(List<BusinessLoopAction> actions)
    {
        if (size(actions) == 0)
        {
            throw new ServiceException("Business loop actions cannot be empty");
        }
        if (actions.size() > MAX_ACTIONS)
        {
            throw new ServiceException("Business loop action count exceeds limit");
        }
        Set<String> actionCodes = new HashSet<String>();
        boolean hasRequiredAction = false;
        for (BusinessLoopAction action : actions)
        {
            if (action == null)
            {
                throw new ServiceException("Business loop action cannot be empty");
            }
            if (StringUtils.isBlank(action.getCode()) || !ACTION_CODE.matcher(action.getCode()).matches())
            {
                throw new ServiceException("Business loop action code is invalid");
            }
            if (!actionCodes.add(action.getCode()))
            {
                throw new ServiceException("Business loop action code duplicated: " + action.getCode());
            }
            hasRequiredAction = hasRequiredAction || action.isRequired();
        }
        if (!hasRequiredAction)
        {
            throw new ServiceException("Business loop must contain at least one required action");
        }
    }

    private int countStateTransitions(BusinessLoopPlan plan)
    {
        int count = 0;
        if (plan.getStateMachines() != null)
        {
            for (BusinessLoopStateMachine stateMachine : plan.getStateMachines())
            {
                if (stateMachine != null)
                {
                    count += size(stateMachine.getTransitions());
                }
            }
        }
        if (plan.getActions() != null)
        {
            for (BusinessLoopAction action : plan.getActions())
            {
                if (action != null)
                {
                    count += size(action.getStateTransitions());
                }
            }
        }
        return count;
    }

    private int size(List<?> items)
    {
        return items == null ? 0 : items.size();
    }
}
