package cn.ibizlab.codegen.templating;

import cn.ibizlab.codegen.model.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.experimental.Accessors;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.nio.file.Paths;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

@Getter
@Setter
@NoArgsConstructor
@Accessors(chain = true)
public class TemplateDefinition {
    private String templateFile;

    private String absolutePath;

    private String templateDir;

    protected TemplateFileType templateType;

    private String subType;

    protected CliData templateDatas;

    public TemplateDefinition(String templateFile) {

    }

    public TemplateDefinition(String templateFile,String templateDir) {
        if (templateFile == null) throw new IllegalArgumentException("templateFile may not be null.");

        this.templateDir=templateDir;
        this.templateFile = templateFile;
        this.templateType = getType(Paths.get(this.templateFile));
        CliData data=ModelStorage.getInstance().getTemplateData(this.templateType);
        if(StringUtils.isEmpty(subType))
            this.templateDatas = data;
        else
            this.templateDatas = data.getSubData(subType);
    }


    private TemplateFileType getType(Path path)
    {
        if(path==null)
            return TemplateFileType.supportingFiles;

        if(StringUtils.isEmpty(path.getFileName()))
            return TemplateFileType.supportingFiles;
        String fileName=path.getFileName().toString();
        for(TemplateFileType type:TemplateFileType.values())
        {
            Pattern p = Pattern.compile("\\{\\{([^}]*)\\}\\}");
            Matcher m = p.matcher(fileName);
            while (m.find()) {
                String[] pairs=m.group(1).split("@");
                if(type.name().equalsIgnoreCase(pairs[0])
                        ||type.value().equalsIgnoreCase(pairs[0])
                        ||type.name().endsWith(" "+pairs[0])
                        ||type.value().endsWith(" "+pairs[0])
                        ||type.name().startsWith(pairs[0]+".")
                        ||type.value().startsWith(pairs[0]+".")
                ) {
                    if(pairs.length>1&&(!StringUtils.isEmpty(pairs[1])))
                        this.setSubType(pairs[1]);
                    return type;
                }
            }

        }
        return getType(path.getParent());
    }


    public List<CliOption> getOptions(CliFilter filter)
    {
        List<CliOption> options = new ArrayList<>();
        if(ObjectUtils.isEmpty(filter)||ObjectUtils.isEmpty(filter.getItems()))
            return getTemplateDatas().getOptions();
        Set<String> filters=null;
        String tag=this.getTemplateType().name()+(StringUtils.isEmpty(this.getSubType())?"":("@"+this.getSubType())).toLowerCase();
        if(filter.getItems().containsKey(tag))
            filters=filter.getItems().get(tag);
        else
        {
            tag=this.getTemplateType().name();
            if(filter.getItems().containsKey(tag))
                filters=filter.getItems().get(tag);
            else
                return options;
        }


        for(CliOption option:getTemplateDatas().getOptions())
        {
            BaseModel model=option.getBaseData();
            if(model!=null)
            {
                if(
                        ( (!StringUtils.isEmpty(model.getCodeName())) && filters.contains(model.getCodeName()) )
                        || ( (!StringUtils.isEmpty(model.getName())) && filters.contains(model.getName()) )
                )
                {
                    boolean matched=true;
                    for(String key:filter.getItems().keySet())
                    {
                        Set<String> subFilters=filter.getItems().get(key);
                        TemplateFileType type=TemplateFileType.forTemplateType(key.split("@")[0]);
                        if(type==null)
                            continue;
                        if(type.name().equalsIgnoreCase(this.templateType.name()))
                            continue;
                        BaseModel exModel=option.getBaseData(type.name());
                        if(exModel==null)
                            exModel=option.getBaseData(type.value());
                        if(exModel!=null) {
                            matched=( (!StringUtils.isEmpty(exModel.getCodeName())) && subFilters.contains(exModel.getCodeName()) )
                                    || ( (!StringUtils.isEmpty(exModel.getName())) && subFilters.contains(exModel.getName()) );
                        }
                        else
                        {
                            String path=option.getStringValue(type.value());
                            if(!StringUtils.isEmpty(path))
                                matched=subFilters.contains(path);
                            else
                                continue;
                        }
                        if(!matched)
                            break;
                    }
                    if(matched)
                        options.add(option);
                }
            }
        }


        return options;
    }

}
