<?php

namespace App\Tests\unit\core\legacy\Statistics;

use App\Legacy\ModuleNameMapperHandler;
use App\Tests\UnitTester;
use BeanFactory;
use Codeception\Test\Unit;
use DateInterval;
use DateTime;
use Doctrine\ORM\EntityManagerInterface;
use Exception;
use Lead;
use App\Tests\_mock\Mock\core\legacy\Statistics\LeadDaysOpenMock;

/**
 * Class LeadDaysOpenTest
 * @package App\Tests\unit\core\legacy\Statistics
 */
class LeadDaysOpenTest extends Unit
{
    /**
     * @var UnitTester
     */
    protected $tester;

    /**
     * @var LeadDaysOpenMock
     */
    private $handler;

    /**
     * @throws Exception
     */
    protected function _before(): void
    {
        $projectDir = $this->tester->getProjectDir();
        $legacyDir = $this->tester->getLegacyDir();
        $legacySessionName = $this->tester->getLegacySessionName();
        $defaultSessionName = $this->tester->getDefaultSessionName();

        $legacyScope = $this->tester->getLegacyScope();

        $moduleNameMapper = new ModuleNameMapperHandler(
            $projectDir,
            $legacyDir,
            $legacySessionName,
            $defaultSessionName,
            $legacyScope
        );


        /** @var EntityManagerInterface $entityManager */
        $entityManager = $this->makeEmpty(
            EntityManagerInterface::class
        );

        $this->handler = new LeadDaysOpenMock(
            $projectDir,
            $legacyDir,
            $legacySessionName,
            $defaultSessionName,
            $legacyScope,
            $moduleNameMapper,
            $entityManager
        );
    }

    /**
     * Test Unsupported context module
     * @throws Exception
     */
    public function testUnsupportedContextModule(): void
    {
        $this->handler->reset();
        $dateString = $this->getPastDateString(2) . ' 12:00:00';
        $bean = $this->buildLead($dateString);

        $this->handler->setLead($bean);

        $result = $this->handler->getData([
            'context' => [
                'module' => 'accounts',
                'id' => '12345',
            ]
        ]);

        static::assertNotNull($result);
        static::assertNotNull($result->getData());
        static::assertNotNull($result->getMetadata());
        static::assertIsArray($result->getData());
        static::assertIsArray($result->getMetadata());
        static::assertEquals('lead-days-open', $result->getId());
        static::assertArrayHasKey('type', $result->getMetadata());
        static::assertEquals('single-value-statistic', $result->getMetadata()['type']);
        static::assertArrayHasKey('dataType', $result->getMetadata());
        static::assertEquals('varchar', $result->getMetadata()['dataType']);
        static::assertArrayHasKey('value', $result->getData());
        static::assertEquals('-', $result->getData()['value']);
    }

    /**
     * Test Converted Status Calculation
     * @throws Exception
     */
    public function testConvertedStatusCalculation(): void
    {
        $this->handler->reset();

        $closedDateString = $this->getPastDateString(2) . ' 19:00:00';
        $rows = [
            [
                'after_value_string' => 'Converted',
                'first_update' => $closedDateString,
                'last_update' => $closedDateString,
            ],
        ];
        $this->handler->setMockQueryResult($rows);

        $dateString = $this->getPastDateString(4) . ' 16:00:00';

        $bean = $this->buildLead($dateString);
        $bean->status = 'Converted';

        $this->handler->setLead($bean);

        $result = $this->handler->getData([
            'context' => [
                'module' => 'leads',
                'id' => '12345',
            ]
        ]);

        static::assertNotNull($result);
        static::assertNotNull($result->getData());
        static::assertNotNull($result->getMetadata());
        static::assertIsArray($result->getData());
        static::assertIsArray($result->getMetadata());
        static::assertArrayHasKey('value', $result->getData());
        static::assertEquals('2', $result->getData()['value']);
        static::assertEquals('lead-days-open', $result->getId());
        static::assertArrayHasKey('type', $result->getMetadata());
        static::assertEquals('single-value-statistic', $result->getMetadata()['type']);
        static::assertArrayHasKey('dataType', $result->getMetadata());
        static::assertEquals('int', $result->getMetadata()['dataType']);

    }

    /**
     * Test Dead Status Calculation
     * @throws Exception
     */
    public function testDeadStatusCalculation(): void
    {
        $this->handler->reset();
        $closedDateString = $this->getPastDateString(2) . ' 19:00:00';
        $rows = [
            [
                'after_value_string' => 'Dead',
                'first_update' => $closedDateString,
                'last_update' => $closedDateString,
            ],
        ];
        $this->handler->setMockQueryResult($rows);

        $dateString = $this->getPastDateString(4) . ' 16:00:00';

        $bean = $this->buildLead($dateString);
        $bean->status = 'Dead';

        $this->handler->setLead($bean);

        $result = $this->handler->getData([
            'context' => [
                'module' => 'leads',
                'id' => '12345',
            ]
        ]);

        static::assertNotNull($result);
        static::assertNotNull($result->getData());
        static::assertNotNull($result->getMetadata());
        static::assertIsArray($result->getData());
        static::assertIsArray($result->getMetadata());
        static::assertArrayHasKey('value', $result->getData());
        static::assertEquals('2', $result->getData()['value']);
        static::assertEquals('lead-days-open', $result->getId());
        static::assertArrayHasKey('type', $result->getMetadata());
        static::assertEquals('single-value-statistic', $result->getMetadata()['type']);
        static::assertArrayHasKey('dataType', $result->getMetadata());
        static::assertEquals('int', $result->getMetadata()['dataType']);

    }

    /**
     * Test Recycled Status Calculation
     * @throws Exception
     */
    public function testRecycledStatusCalculation(): void
    {
        $this->handler->reset();
        $closedDateString = $this->getPastDateString(2) . ' 09:00:00';
        $rows = [
            [
                'after_value_string' => 'Recycled',
                'first_update' => $closedDateString,
                'last_update' => $closedDateString,
            ],
        ];
        $this->handler->setMockQueryResult($rows);

        $dateString = $this->getPastDateString(4) . ' 16:00:00';

        $bean = $this->buildLead($dateString);
        $bean->status = 'Recycled';

        $this->handler->setLead($bean);

        $result = $this->handler->getData([
            'context' => [
                'module' => 'leads',
                'id' => '12345',
            ]
        ]);

        static::assertNotNull($result);
        static::assertNotNull($result->getData());
        static::assertNotNull($result->getMetadata());
        static::assertIsArray($result->getData());
        static::assertIsArray($result->getMetadata());
        static::assertArrayHasKey('value', $result->getData());
        static::assertEquals('2', $result->getData()['value']);
        static::assertEquals('lead-days-open', $result->getId());
        static::assertArrayHasKey('type', $result->getMetadata());
        static::assertEquals('single-value-statistic', $result->getMetadata()['type']);
        static::assertArrayHasKey('dataType', $result->getMetadata());
        static::assertEquals('int', $result->getMetadata()['dataType']);

    }

    /**
     * Test Assigned Audit Calculation
     * @throws Exception
     */
    public function testStatusAuditCalculation(): void
    {
        $qualificationChangeDateString = $this->getPastDateString(3) . ' 09:00:00';

        $rows = [
            [
                'after_value_string' => 'Assigned',
                'first_update' => $qualificationChangeDateString,
                'last_update' => $qualificationChangeDateString,
            ],
        ];

        $this->handler->setMockQueryResult($rows);

        $dateString = $this->getPastDateTimeString(5);

        $bean = $this->buildLead($dateString);
        $bean->status = 'Assigned';

        $this->handler->setLead($bean);

        $result = $this->handler->getData([
            'context' => [
                'module' => 'leads',
                'id' => '12345',
            ]
        ]);

        static::assertNotNull($result);
        static::assertNotNull($result->getData());
        static::assertNotNull($result->getMetadata());
        static::assertIsArray($result->getData());
        static::assertIsArray($result->getMetadata());
        static::assertArrayHasKey('value', $result->getData());
        static::assertEquals('5', $result->getData()['value']);
        static::assertEquals('lead-days-open', $result->getId());
        static::assertArrayHasKey('type', $result->getMetadata());
        static::assertEquals('single-value-statistic', $result->getMetadata()['type']);
        static::assertArrayHasKey('dataType', $result->getMetadata());
        static::assertEquals('int', $result->getMetadata()['dataType']);

    }

    /**
     * @param int $days
     * @return string
     * @throws Exception
     */
    protected function getPastDateString(int $days): string
    {
        $now = new DateTime();
        $now->sub(new DateInterval('P' . $days . 'D'));

        return $now->format('Y-m-d');
    }

    /**
     * @param int $days
     * @return string
     * @throws Exception
     */
    protected function getPastDateTimeString(int $days): string
    {
        $now = new DateTime();
        $now->sub(new DateInterval('P' . $days . 'DT1H'));

        return $now->format('Y-m-d H:i:s');
    }

    /**
     * @param string $dateString
     * @return Lead
     */
    protected function buildLead(string $dateString): Lead
    {
        /** @var Lead $bean */
        $bean = BeanFactory::newBean('Leads');
        $bean->date_entered = $dateString;
        $bean->id = '12355';

        return $bean;
    }
}
