<?php

/**
 * SPDX-FileCopyrightText: 2016-2024 Nextcloud GmbH and Nextcloud contributors
 * SPDX-FileCopyrightText: 2016 ownCloud, Inc.
 * SPDX-License-Identifier: AGPL-3.0-only
 */
namespace OCA\DAV\Tests\unit\CardDAV;

use OCA\DAV\CardDAV\AddressBook;
use OCA\DAV\CardDAV\ImageExportPlugin;
use OCA\DAV\CardDAV\PhotoCache;
use OCP\Files\NotFoundException;
use OCP\Files\SimpleFS\ISimpleFile;
use Sabre\CardDAV\Card;
use Sabre\DAV\Node;
use Sabre\DAV\Server;
use Sabre\DAV\Tree;
use Sabre\HTTP\RequestInterface;
use Sabre\HTTP\ResponseInterface;
use Test\TestCase;

class ImageExportPluginTest extends TestCase {
	/** @var ResponseInterface|\PHPUnit\Framework\MockObject\MockObject */
	private $response;
	/** @var RequestInterface|\PHPUnit\Framework\MockObject\MockObject */
	private $request;
	/** @var ImageExportPlugin|\PHPUnit\Framework\MockObject\MockObject */
	private $plugin;
	/** @var Server */
	private $server;
	/** @var Tree|\PHPUnit\Framework\MockObject\MockObject */
	private $tree;
	/** @var PhotoCache|\PHPUnit\Framework\MockObject\MockObject */
	private $cache;

	protected function setUp(): void {
		parent::setUp();

		$this->request = $this->createMock(RequestInterface::class);
		$this->response = $this->createMock(ResponseInterface::class);
		$this->server = $this->createMock(Server::class);
		$this->tree = $this->createMock(Tree::class);
		$this->server->tree = $this->tree;
		$this->cache = $this->createMock(PhotoCache::class);

		$this->plugin = $this->getMockBuilder(ImageExportPlugin::class)
			->setMethods(['getPhoto'])
			->setConstructorArgs([$this->cache])
			->getMock();
		$this->plugin->initialize($this->server);
	}

	/**
	 * @dataProvider providesQueryParams
	 * @param $param
	 */
	public function testQueryParams($param): void {
		$this->request->expects($this->once())->method('getQueryParameters')->willReturn($param);
		$result = $this->plugin->httpGet($this->request, $this->response);
		$this->assertTrue($result);
	}

	public function providesQueryParams() {
		return [
			[[]],
			[['1']],
			[['foo' => 'bar']],
		];
	}

	public function testNoCard(): void {
		$this->request->method('getQueryParameters')
			->willReturn([
				'photo'
			]);
		$this->request->method('getPath')
			->willReturn('user/book/card');

		$node = $this->createMock(Node::class);
		$this->tree->method('getNodeForPath')
			->with('user/book/card')
			->willReturn($node);

		$result = $this->plugin->httpGet($this->request, $this->response);
		$this->assertTrue($result);
	}

	public function dataTestCard() {
		return [
			[null, false],
			[null, true],
			[32, false],
			[32, true],
		];
	}

	/**
	 * @dataProvider dataTestCard
	 *
	 * @param $size
	 * @param bool $photo
	 */
	public function testCard($size, $photo): void {
		$query = ['photo' => null];
		if ($size !== null) {
			$query['size'] = $size;
		}

		$this->request->method('getQueryParameters')
			->willReturn($query);
		$this->request->method('getPath')
			->willReturn('user/book/card');

		$card = $this->createMock(Card::class);
		$card->method('getETag')
			->willReturn('"myEtag"');
		$card->method('getName')
			->willReturn('card');
		$book = $this->createMock(AddressBook::class);
		$book->method('getResourceId')
			->willReturn(1);

		$this->tree->method('getNodeForPath')
			->willReturnCallback(function ($path) use ($card, $book) {
				if ($path === 'user/book/card') {
					return $card;
				} elseif ($path === 'user/book') {
					return $book;
				}
				$this->fail();
			});

		$size = $size === null ? -1 : $size;

		if ($photo) {
			$file = $this->createMock(ISimpleFile::class);
			$file->method('getMimeType')
				->willReturn('image/jpeg');
			$file->method('getContent')
				->willReturn('imgdata');

			$this->cache->method('get')
				->with(1, 'card', $size, $card)
				->willReturn($file);

			$this->response->expects($this->exactly(4))
				->method('setHeader')
				->withConsecutive(
					['Cache-Control', 'private, max-age=3600, must-revalidate'],
					['Etag', '"myEtag"'],
					['Content-Type', 'image/jpeg'],
					['Content-Disposition', 'attachment; filename=card.jpg'],
				);

			$this->response->expects($this->once())
				->method('setStatus')
				->with(200);
			$this->response->expects($this->once())
				->method('setBody')
				->with('imgdata');
		} else {
			$this->response->expects($this->exactly(2))
				->method('setHeader')
				->withConsecutive(
					['Cache-Control', 'private, max-age=3600, must-revalidate'],
					['Etag', '"myEtag"'],
				);
			$this->cache->method('get')
				->with(1, 'card', $size, $card)
				->willThrowException(new NotFoundException());
			$this->response->expects($this->once())
				->method('setStatus')
				->with(404);
		}

		$result = $this->plugin->httpGet($this->request, $this->response);
		$this->assertFalse($result);
	}
}
