<?php
/**
 * Copyright 2016 Adobe
 * All Rights Reserved.
 */
declare(strict_types=1);

namespace Magento\Catalog\Test\Unit\Block\Category\Plugin;

use Magento\Catalog\Block\Category\Plugin\PriceBoxTags;
use Magento\Customer\Model\Session;
use Magento\Directory\Model\Currency;
use Magento\Framework\App\ScopeInterface;
use Magento\Framework\App\ScopeResolverInterface;
use Magento\Framework\DataObject;
use Magento\Framework\Model\ResourceModel\AbstractResource;
use Magento\Framework\Pricing\PriceCurrencyInterface;
use Magento\Framework\Pricing\Render\PriceBox;
use Magento\Framework\Pricing\SaleableInterface;
use Magento\Framework\Stdlib\DateTime\TimezoneInterface;
use Magento\Framework\TestFramework\Unit\Helper\MockCreationTrait;
use Magento\Framework\TestFramework\Unit\Helper\ObjectManager;
use Magento\Tax\Model\Calculation;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;

/**
 * @SuppressWarnings(PHPMD.CouplingBetweenObjects)
 */
class PriceBoxTagsTest extends TestCase
{
    use MockCreationTrait;
    /**
     * @var PriceCurrencyInterface|MockObject
     */
    private $priceCurrencyInterface;

    /**
     * @var Currency|MockObject
     */
    private $currency;

    /**
     * @var TimezoneInterface|MockObject
     */
    private $timezoneInterface;

    /**
     * @var ScopeResolverInterface|MockObject
     */
    private $scopeResolverInterface;

    /**
     * @var Session|MockObject
     */
    private $session;

    /**
     * @var Calculation|MockObject
     */
    private $taxCalculation;

    /**
     * @var PriceBoxTags
     */
    private $priceBoxTags;

    protected function setUp(): void
    {
        $this->priceCurrencyInterface = $this->createMock(PriceCurrencyInterface::class);
        $this->currency = $this->createPartialMock(Currency::class, ['getCode']);
        $this->timezoneInterface = $this->createMock(TimezoneInterface::class);
        $this->scopeResolverInterface = $this->createMock(ScopeResolverInterface::class);
        $this->session = $this->createPartialMockWithReflection(
            Session::class,
            ['getCustomerGroupId', 'getDefaultTaxBillingAddress', 'getDefaultTaxShippingAddress',
             'getCustomerTaxClassId', 'getCustomerId']
        );
        $this->taxCalculation = $this->createPartialMock(
            Calculation::class,
            ['getRateRequest', 'getResource']
        );
        $objectManager = new ObjectManager($this);
        $this->priceBoxTags = $objectManager->getObject(
            PriceBoxTags::class,
            [
                'priceCurrency' => $this->priceCurrencyInterface,
                'dateTime' => $this->timezoneInterface,
                'scopeResolver' => $this->scopeResolverInterface,
                'customerSession' => $this->session,
                'taxCalculation' => $this->taxCalculation
            ]
        );
    }

    public function testAfterGetCacheKey()
    {
        $date = date('Ymd');
        $currencyCode = 'USD';
        $result = 'result_string';
        $billingAddress = ['billing_address'];
        $shippingAddress = ['shipping_address'];
        $scopeId = 1;
        $customerGroupId = 2;
        $customerTaxClassId = 3;
        $customerId = 4;
        $rateIds = [5,6];
        $expected = implode(
            '-',
            [
                $result,
                $currencyCode,
                $date,
                $scopeId,
                $customerGroupId,
                implode('_', $rateIds)
            ]
        );

        $priceBox = $this->createPartialMock(PriceBox::class, ['getSaleableItem']);
        $this->priceCurrencyInterface->expects($this->once())->method('getCurrency')->willReturn($this->currency);
        $this->currency->expects($this->once())->method('getCode')->willReturn($currencyCode);
        $scope = $this->createMock(ScopeInterface::class);
        $this->scopeResolverInterface->method('getScope')->willReturn($scope);
        $scope->method('getId')->willReturn($scopeId);
        $dateTime = $this->createPartialMock(\DateTime::class, ['format']);
        $this->timezoneInterface->expects($this->any())->method('scopeDate')->with($scopeId)->willReturn($dateTime);
        $dateTime->expects($this->any())->method('format')->with('Ymd')->willReturn($date);
        
        $this->session->expects($this->once())->method('getCustomerGroupId')->willReturn($customerGroupId);
        $this->session->expects($this->once())->method('getDefaultTaxBillingAddress')->willReturn($billingAddress);
        $this->session->expects($this->once())->method('getDefaultTaxShippingAddress')->willReturn($shippingAddress);
        $this->session->expects($this->once())->method('getCustomerTaxClassId')->willReturn($customerTaxClassId);
        $this->session->expects($this->once())->method('getCustomerId')->willReturn($customerId);
        
        $rateRequest = $this->createMock(DataObject::class);
        $this->taxCalculation->expects($this->once())->method('getRateRequest')->with(
            new DataObject($shippingAddress),
            new DataObject($billingAddress),
            $customerTaxClassId,
            $scopeId,
            $customerId
        )->willReturn($rateRequest);
        $salableInterface = $this->createPartialMockWithReflection(
            SaleableInterface::class,
            ['getTaxClassId', 'getPriceInfo', 'getTypeId', 'getId', 'getQty']
        );
        $salableInterface->expects($this->once())->method('getTaxClassId')->willReturn($customerTaxClassId);
        $salableInterface->method('getPriceInfo')->willReturn(null);
        $salableInterface->method('getTypeId')->willReturn('simple');
        $salableInterface->method('getId')->willReturn(1);
        $salableInterface->method('getQty')->willReturn(1);
        $priceBox->expects($this->once())->method('getSaleableItem')->willReturn($salableInterface);
        $resource = $this->createPartialMockWithReflection(
            AbstractResource::class,
            ['getRateIds', '_construct', 'getConnection']
        );
        $resource->expects($this->once())->method('getRateIds')->with($rateRequest)->willReturn($rateIds);
        $resource->method('_construct')->willReturn(null);
        $resource->method('getConnection')->willReturn(null);
        $this->taxCalculation->expects($this->once())->method('getResource')->willReturn($resource);

        $this->assertEquals($expected, $this->priceBoxTags->afterGetCacheKey($priceBox, $result));
    }
}
