// Copyright (C) 2020 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.gerrit.httpd.raw;

import static com.google.common.collect.ImmutableList.toImmutableList;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Ints;
import com.google.gerrit.common.Nullable;
import com.google.gerrit.common.UsedAt;
import com.google.gerrit.common.UsedAt.Project;
import com.google.gerrit.extensions.client.ListChangesOption;
import com.google.gerrit.extensions.restapi.Url;
import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/** Helper for generating preloading parts of {@code index.html}. */
@UsedAt(Project.GOOGLE)
public class IndexPreloadingUtil {
  enum RequestedPage {
    CHANGE,
    DIFF,
    DASHBOARD,
    PROFILE,
    PAGE_WITHOUT_PRELOADING,
  }

  public static final String CHANGE_CANONICAL_PATH = "/c/(?<project>.+)/\\+/(?<changeNum>\\d+)";
  public static final String BASE_PATCH_NUM_PATH_PART = "(/(-?\\d+|edit)(\\.\\.(\\d+|edit))?)";
  public static final Pattern CHANGE_URL_PATTERN =
      Pattern.compile(CHANGE_CANONICAL_PATH + BASE_PATCH_NUM_PATH_PART + "?" + "/?$");
  public static final Pattern DIFF_URL_PATTERN =
      Pattern.compile(CHANGE_CANONICAL_PATH + BASE_PATCH_NUM_PATH_PART + "(/(.+))" + "/?$");
  public static final Pattern DASHBOARD_PATTERN = Pattern.compile("/dashboard/self$");
  public static final Pattern PROFILE_PATTERN = Pattern.compile("/profile/self$");
  public static final String ROOT_PATH = "/";

  // These queries should be kept in sync with PolyGerrit:
  // polygerrit-ui/app/elements/core/gr-navigation/gr-navigation.ts
  public static final String DASHBOARD_HAS_UNPUBLISHED_DRAFTS_QUERY = "has:draft limit:10";
  public static final String YOUR_TURN = "attention:${user} limit:25";
  public static final String DASHBOARD_WORK_IN_PROGRESS_QUERY =
      "is:open owner:${user} is:wip limit:25";
  public static final String DASHBOARD_OUTGOING_QUERY = "is:open owner:${user} -is:wip limit:25";
  public static final String DASHBOARD_INCOMING_QUERY =
      "is:open -owner:${user} -is:wip reviewer:${user} limit:25";
  public static final String CC_QUERY = "is:open -is:wip cc:${user} limit:10";
  public static final String DASHBOARD_RECENTLY_CLOSED_QUERY =
      "is:closed (-is:wip OR owner:self) "
          + "(owner:${user} OR reviewer:${user} OR cc:${user}) "
          + "-age:4w limit:10";
  public static final String NEW_USER = "owner:${user} limit:1";

  public static final String SELF_DASHBOARD_HAS_UNPUBLISHED_DRAFTS_QUERY =
      DASHBOARD_HAS_UNPUBLISHED_DRAFTS_QUERY.replaceAll("\\$\\{user}", "self");
  public static final String SELF_YOUR_TURN = YOUR_TURN.replaceAll("\\$\\{user}", "self");
  public static final ImmutableList<String> SELF_DASHBOARD_QUERIES =
      Stream.of(
              DASHBOARD_WORK_IN_PROGRESS_QUERY,
              DASHBOARD_OUTGOING_QUERY,
              DASHBOARD_INCOMING_QUERY,
              CC_QUERY,
              DASHBOARD_RECENTLY_CLOSED_QUERY,
              NEW_USER)
          .map(query -> query.replaceAll("\\$\\{user}", "self"))
          .collect(toImmutableList());
  public static final ImmutableSet<ListChangesOption> DASHBOARD_OPTIONS =
      ImmutableSet.of(
          ListChangesOption.LABELS,
          ListChangesOption.DETAILED_ACCOUNTS,
          ListChangesOption.SUBMIT_REQUIREMENTS,
          ListChangesOption.STAR);

  public static final ImmutableSet<ListChangesOption> CHANGE_DETAIL_OPTIONS =
      ImmutableSet.of(
          ListChangesOption.ALL_COMMITS,
          ListChangesOption.ALL_REVISIONS,
          ListChangesOption.CHANGE_ACTIONS,
          ListChangesOption.DETAILED_ACCOUNTS,
          ListChangesOption.DETAILED_LABELS,
          ListChangesOption.DOWNLOAD_COMMANDS,
          ListChangesOption.MESSAGES,
          ListChangesOption.REVIEWER_UPDATES,
          ListChangesOption.SUBMITTABLE,
          ListChangesOption.WEB_LINKS,
          ListChangesOption.SKIP_DIFFSTAT,
          ListChangesOption.SUBMIT_REQUIREMENTS,
          ListChangesOption.PARENTS);

  @Nullable
  public static String getPath(@Nullable String requestedURL) throws URISyntaxException {
    if (requestedURL == null) {
      return null;
    }
    URI uri = new URI(requestedURL);
    return uri.getPath();
  }

  public static RequestedPage parseRequestedPage(@Nullable String requestedPath) {
    if (requestedPath == null) {
      return RequestedPage.PAGE_WITHOUT_PRELOADING;
    }

    Optional<String> changeRequestsPath =
        computeChangeRequestsPath(requestedPath, RequestedPage.CHANGE);
    if (changeRequestsPath.isPresent()) {
      return RequestedPage.CHANGE;
    }

    changeRequestsPath = computeChangeRequestsPath(requestedPath, RequestedPage.DIFF);
    if (changeRequestsPath.isPresent()) {
      return RequestedPage.DIFF;
    }

    Matcher dashboardMatcher = IndexPreloadingUtil.DASHBOARD_PATTERN.matcher(requestedPath);
    if (dashboardMatcher.matches()) {
      return RequestedPage.DASHBOARD;
    }

    Matcher profileMatcher = IndexPreloadingUtil.PROFILE_PATTERN.matcher(requestedPath);
    if (profileMatcher.matches()) {
      return RequestedPage.PROFILE;
    }

    if (ROOT_PATH.equals(requestedPath)) {
      return RequestedPage.DASHBOARD;
    }

    return RequestedPage.PAGE_WITHOUT_PRELOADING;
  }

  public static Optional<String> computeChangeRequestsPath(
      String requestedURL, RequestedPage page) {
    Matcher matcher;
    switch (page) {
      case CHANGE:
        matcher = CHANGE_URL_PATTERN.matcher(requestedURL);
        break;
      case DIFF:
        matcher = DIFF_URL_PATTERN.matcher(requestedURL);
        break;
      case DASHBOARD:
      case PROFILE:
      case PAGE_WITHOUT_PRELOADING:
      default:
        return Optional.empty();
    }

    if (matcher.matches()) {
      Integer changeId = Ints.tryParse(matcher.group("changeNum"));
      if (changeId != null) {
        return Optional.of("changes/" + Url.encode(matcher.group("project")) + "~" + changeId);
      }
    }
    return Optional.empty();
  }

  public static Optional<Integer> computeChangeNum(String requestedURL, RequestedPage page) {
    Matcher matcher;
    switch (page) {
      case CHANGE:
        matcher = CHANGE_URL_PATTERN.matcher(requestedURL);
        break;
      case DIFF:
        matcher = DIFF_URL_PATTERN.matcher(requestedURL);
        break;
      case DASHBOARD:
      case PROFILE:
      case PAGE_WITHOUT_PRELOADING:
      default:
        return Optional.empty();
    }

    if (matcher.matches()) {
      Integer changeNum = Ints.tryParse(matcher.group("changeNum"));
      if (changeNum != null) {
        return Optional.of(changeNum);
      }
    }
    return Optional.empty();
  }

  public static List<String> computeDashboardQueryList() {
    List<String> queryList = new ArrayList<>();
    queryList.add(SELF_DASHBOARD_HAS_UNPUBLISHED_DRAFTS_QUERY);
    queryList.add(SELF_YOUR_TURN);
    queryList.addAll(SELF_DASHBOARD_QUERIES);

    return queryList;
  }

  private IndexPreloadingUtil() {}
}
