// Copyright 2020 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import "base/ios/ios_util.h"
#import "base/strings/stringprintf.h"
#import "ios/chrome/browser/shared/public/features/features.h"
#import "ios/chrome/test/earl_grey/chrome_actions.h"
#import "ios/chrome/test/earl_grey/chrome_earl_grey.h"
#import "ios/chrome/test/earl_grey/chrome_matchers.h"
#import "ios/chrome/test/earl_grey/chrome_test_case.h"
#import "ios/testing/earl_grey/earl_grey_test.h"
#import "ios/web/public/test/element_selector.h"
#import "net/test/embedded_test_server/embedded_test_server.h"
#import "net/test/embedded_test_server/http_request.h"
#import "net/test/embedded_test_server/http_response.h"

namespace {

const char kWebShareButtonId[] = "shareButton";

const char kWebShareStatusSuccess[] = "success";
const char kWebShareStatusFailure[] = "failure";

const char kWebShareValidLinkUrl[] = "/share_link.html";
const char kWebShareFileUrl[] = "/share_file.html";
const char kWebShareRelativeLinkUrl[] = "/share_relative_link.html";
const char kWebShareRelativeFilenameFileUrl[] = "/share_filename_file.html";
const char kWebShareUrlObjectUrl[] = "/share_url_object.html";

const char kWebSharePageContents[] =
    "<html>"
    "<head>"
    "<script>"
    "async function tryUrl() {"
    "  document.getElementById(\"result\").innerHTML = '';"
    "  try {"
    "    var opts = {url: %s};"
    "    await navigator.share(opts);"
    "    document.getElementById(\"result\").innerHTML = 'success';"
    "  } catch {"
    "    document.getElementById(\"result\").innerHTML = 'failure';"
    "  }"
    "}"
    "</script>"
    "</head><body>"
    "<button id=\"shareButton\" onclick=\"tryUrl()\">Share</button>"
    "<div id=\"result\"></div>"
    "</body></html>";

std::unique_ptr<net::test_server::HttpResponse> HandleRequest(
    const net::test_server::HttpRequest& request) {
  auto http_response = std::make_unique<net::test_server::BasicHttpResponse>();
  http_response->set_code(net::HTTP_OK);
  http_response->set_content_type("text/html");

  if (request.relative_url == kWebShareValidLinkUrl) {
    std::string content =
        base::StringPrintf(kWebSharePageContents, "\"https://example.com\"");
    http_response->set_content(content);
  } else if (request.relative_url == kWebShareFileUrl) {
    std::string content =
        base::StringPrintf(kWebSharePageContents, "\"file:///Users/u/data\"");
    http_response->set_content(content);
  } else if (request.relative_url == kWebShareRelativeLinkUrl) {
    std::string content =
        base::StringPrintf(kWebSharePageContents, "\"/something.png\"");
    http_response->set_content(content);
  } else if (request.relative_url == kWebShareRelativeFilenameFileUrl) {
    std::string content =
        base::StringPrintf(kWebSharePageContents, "\"filename.zip\"");
    http_response->set_content(content);
  } else if (request.relative_url == kWebShareUrlObjectUrl) {
    std::string content =
        base::StringPrintf(kWebSharePageContents, "window.location");
    http_response->set_content(content);
  } else {
    return nullptr;
  }
  return std::move(http_response);
}

// Taps the Web Share button in the web view.
void TapWebShareButton() {
  [[EarlGrey selectElementWithMatcher:chrome_test_util::WebViewMatcher()]
      performAction:chrome_test_util::TapWebElementUnverified([ElementSelector
                        selectorWithElementID:kWebShareButtonId])];
}

}  // namespace

@interface WebShareTestCase : ChromeTestCase
@end

@implementation WebShareTestCase

- (AppLaunchConfiguration)appConfigurationForTestCase {
  AppLaunchConfiguration config = [super appConfigurationForTestCase];
  return config;
}

- (void)setUp {
  [super setUp];

  self.testServer->RegisterRequestHandler(base::BindRepeating(&HandleRequest));
  GREYAssertTrue(self.testServer->Start(), @"Test server failed to start.");
}

// Tests that a fully specified url can be shared.
- (void)testShareUrl {
  const GURL pageURL = self.testServer->GetURL(kWebShareValidLinkUrl);
  [ChromeEarlGrey loadURL:pageURL];
  TapWebShareButton();

  [ChromeEarlGrey tapButtonInActivitySheetWithID:@"Copy"];

  [ChromeEarlGrey waitForWebStateContainingText:kWebShareStatusSuccess];
}

// Tests that a relative  url can be shared.
- (void)testShareRelativeUrl {
  const GURL pageURL = self.testServer->GetURL(kWebShareRelativeLinkUrl);
  [ChromeEarlGrey loadURL:pageURL];
  TapWebShareButton();

  [ChromeEarlGrey tapButtonInActivitySheetWithID:@"Copy"];

  [ChromeEarlGrey waitForWebStateContainingText:kWebShareStatusSuccess];
}

// Tests that a relative url can be shared when the filename starts with "file".
- (void)testShareRelativeFilenameUrl {
  const GURL pageURL =
      self.testServer->GetURL(kWebShareRelativeFilenameFileUrl);
  [ChromeEarlGrey loadURL:pageURL];
  TapWebShareButton();

  [ChromeEarlGrey tapButtonInActivitySheetWithID:@"Copy"];

  [ChromeEarlGrey waitForWebStateContainingText:kWebShareStatusSuccess];
}

// Tests that a "file://" url can not be shared.
- (void)testShareFileUrl {
  const GURL pageURL = self.testServer->GetURL(kWebShareFileUrl);
  [ChromeEarlGrey loadURL:pageURL];
  TapWebShareButton();

  [ChromeEarlGrey waitForWebStateContainingText:kWebShareStatusFailure];

  // Share sheet should not display.
  [ChromeEarlGrey verifyActivitySheetNotVisible];
}

// Tests that an url object can be shared.
- (void)testShareUrlObject {
  const GURL pageURL = self.testServer->GetURL(kWebShareUrlObjectUrl);
  [ChromeEarlGrey loadURL:pageURL];
  TapWebShareButton();

  [ChromeEarlGrey tapButtonInActivitySheetWithID:@"Copy"];

  [ChromeEarlGrey waitForWebStateContainingText:kWebShareStatusSuccess];
}

@end
