// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:convert';

import 'package:path/path.dart' as p;
import 'package:pub/src/exit_codes.dart' as exit_codes;
import 'package:pub/src/io.dart';
import 'package:shelf/shelf.dart' as shelf;
import 'package:test/test.dart';

import '../descriptor.dart' as d;
import '../test_pub.dart';
import 'utils.dart';

void main() {
  test('archives and uploads a package', () async {
    await servePackages();
    await d.validPackage().create();
    await d.credentialsFile(globalServer, 'access-token').create();
    final pub = await startPublish(globalServer);

    await confirmPublish(pub);
    handleUploadForm(globalServer);
    handleUpload(globalServer);

    globalServer.expect('GET', '/create', (request) {
      return shelf.Response.ok(
        jsonEncode({
          'success': {'message': 'Package test_pkg 1.0.0 uploaded!'},
        }),
      );
    });

    expect(pub.stdout, emits(startsWith('Uploading...')));
    expect(
      pub.stdout,
      emits('Message from server: Package test_pkg 1.0.0 uploaded!'),
    );
    await pub.shouldExit(exit_codes.SUCCESS);
  });

  test('archives and uploads a package using token', () async {
    await servePackages();
    await d.validPackage().create();
    await d.tokensFile({
      'version': 1,
      'hosted': [
        {'url': globalServer.url, 'token': 'access-token'},
      ],
    }).create();
    final pub = await startPublish(globalServer);

    await confirmPublish(pub);
    handleUploadForm(globalServer);
    handleUpload(globalServer);

    globalServer.expect('GET', '/create', (request) {
      return shelf.Response.ok(
        jsonEncode({
          'success': {'message': 'Package test_pkg 1.0.0 uploaded!'},
        }),
      );
    });

    expect(pub.stdout, emits(startsWith('Uploading...')));
    expect(
      pub.stdout,
      emits('Message from server: Package test_pkg 1.0.0 uploaded!'),
    );
    await pub.shouldExit(exit_codes.SUCCESS);
  });

  test('publishes to hosted-url with path', () async {
    await servePackages();
    await d.validPackage().create();
    await d.tokensFile({
      'version': 1,
      'hosted': [
        {'url': '${globalServer.url}/sub/folder', 'env': 'TOKEN'},
      ],
    }).create();
    final pub = await startPublish(
      globalServer,
      path: '/sub/folder',
      overrideDefaultHostedServer: false,
      environment: {'TOKEN': 'access-token'},
    );

    await confirmPublish(pub);
    handleUploadForm(globalServer, path: '/sub/folder');
    handleUpload(globalServer);

    globalServer.expect('GET', '/create', (request) {
      return shelf.Response.ok(
        jsonEncode({
          'success': {'message': 'Package test_pkg 1.0.0 uploaded!'},
        }),
      );
    });

    expect(pub.stdout, emits(startsWith('Uploading...')));
    expect(
      pub.stdout,
      emits('Message from server: Package test_pkg 1.0.0 uploaded!'),
    );
    await pub.shouldExit(exit_codes.SUCCESS);
  });

  // This is a regression test for #1679. We create a submodule that's not
  // checked out to ensure that file listing doesn't choke on the empty
  // directory.
  test('with an empty Git submodule', () async {
    await d.git('empty').create();

    final repo = d.git(appPath, d.validPackage().contents);
    await repo.create();

    await repo.runGit([
      // Hack to allow testing with local submodules after CVE-2022-39253.
      '-c',
      'protocol.file.allow=always',
      'submodule',
      'add',
      '--',
      '../empty',
      'empty',
    ]);
    await repo.commit();

    deleteEntry(p.join(d.sandbox, appPath, 'empty'));
    await d.dir(p.join(appPath, 'empty')).create();

    await servePackages();
    await d.credentialsFile(globalServer, 'access-token').create();
    final pub = await startPublish(globalServer);

    await confirmPublish(pub);
    handleUploadForm(globalServer);
    handleUpload(globalServer);

    globalServer.expect('GET', '/create', (request) {
      return shelf.Response.ok(
        jsonEncode({
          'success': {'message': 'Package test_pkg 1.0.0\u0000uploaded!'},
          // The \u0000 should be sanitized to a space.
        }),
      );
    });

    expect(pub.stdout, emits(startsWith('Uploading...')));
    expect(
      pub.stdout,
      emits('Message from server: Package test_pkg 1.0.0 uploaded!'),
    );
    await pub.shouldExit(exit_codes.SUCCESS);
  });

  // TODO(nweiz): Once a multipart/form-data parser in Dart exists, we should
  // test that "pub lish" chooses the correct files to publish.
}
