package com.jetbrains.python.debugger;

import com.google.common.collect.Lists;
import com.intellij.openapi.util.text.StringUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Arrays;
import java.util.List;

/**
 * @author traff
 */
public class PySignature {
  private static final String UNION_PREFIX = "Union[";
  private final String myFile;
  private final String myFunctionName;

  private NamedParameter myReturnType = null;

  private final List<NamedParameter> myArgs = Lists.newArrayList();

  public PySignature(@NotNull String file, @NotNull String name) {
    myFile = file;
    myFunctionName = name;
  }

  @Nullable
  public String getArgTypeQualifiedName(@NotNull String name) {
    for (NamedParameter param : myArgs) {
      if (name.equals(param.getName())) {
        return param.getTypeQualifiedName();
      }
    }
    return null;
  }

  @NotNull
  public String getFile() {
    return myFile;
  }

  @NotNull
  public String getFunctionName() {
    return myFunctionName;
  }

  @NotNull
  public List<NamedParameter> getArgs() {
    return myArgs;
  }

  public NamedParameter getReturnType() {
    return myReturnType;
  }

  public PySignature addReturnType(@Nullable String returnType) {
    if (StringUtil.isNotEmpty(returnType)) {
      if (myReturnType != null) {
        myReturnType.addType(returnType);
      }
      else {
        myReturnType = new NamedParameter("", returnType);
      }
    }
    return this;
  }

  @NotNull
  public PySignature addAllArgs(@NotNull PySignature signature) {
    for (NamedParameter param : signature.getArgs()) {
      NamedParameter ourParam = getArgForName(param.getName());
      if (ourParam != null) {
        ourParam.addTypes(param.getTypesList());
      }
      else {
        addArgument(param);
      }
    }
    return this;
  }

  @Nullable
  private NamedParameter getArgForName(String name) {
    for (NamedParameter param : myArgs) {
      if (param.getName().equals(name)) {
        return param;
      }
    }

    return null;
  }

  @Nullable
  public String getReturnTypeQualifiedName() {
    return myReturnType != null ? myReturnType.getTypeQualifiedName() : null;
  }


  public static class NamedParameter {
    private final String myName;
    private final List<String> myTypes;

    private NamedParameter(@NotNull String name, @NotNull String type) {
      myName = name;

      myTypes = parseTypes(type);
    }

    @NotNull
    private static List<String> parseTypes(@NotNull String type) {
      if (type.startsWith(UNION_PREFIX) && type.endsWith("]")) {
        return Arrays.asList(type.substring(UNION_PREFIX.length(), type.length() - 1).split("\\s*,\\s*"));
      }
      else {
        String[] parts = type.split(" or ");
        return Lists.newArrayList(parts);
      }
    }

    public String getName() {
      return myName;
    }

    public String getTypeQualifiedName() {
      if (myTypes.size() == 1) {
        return noneTypeToNone(myTypes.get(0));
      }
      else {
        return UNION_PREFIX + StringUtil.join(myTypes, NamedParameter::noneTypeToNone, ", ") + "]";
      }
    }

    @Nullable
    private static String noneTypeToNone(@Nullable String type) {
      return "NoneType".equals(type) ? "None" : type;
    }

    public void addType(String type) {
      if (!myTypes.contains(type)) {
        myTypes.add(type);
      }
    }

    public void addTypes(List<String> newTypes) {
      for (String type : newTypes) {
        addType(type);
      }
    }

    public List<String> getTypesList() {
      return myTypes;
    }
  }


  public PySignature addArgument(String name, String type) {
    return addArgument(new NamedParameter(name, type));
  }

  public PySignature addArgument(NamedParameter argument) {
    myArgs.add(argument);
    return this;
  }
}

@@ -213,33 +213,8 @@
 e;%0A%0A
-import java.util.Arrays;%0A
 impo
@@ -2605,17 +2605,22 @@
 urn 
+Lists.new
 Array
-s.as
 List

Create ArrayList instead (EA-81860)