<?php
// Copyright (c) Pickware GmbH. All rights reserved.
// This file is part of software that is released under a proprietary license.
// You must not copy, modify, distribute, make publicly available, or execute
// its contents or parts thereof without express permission by the copyright
// holder, unless otherwise permitted by law.

namespace Shopware\Plugins\ViisonCommon\Components\Plugins;

use Exception;
use Shopware\Components\Model\ModelManager;
use Shopware\CustomModels\ImportExport\Profile as SwagImportExportVersion2Profile;
use SwagImportExport\Models\Profile as SwagImportExportVersion3Profile;
use Symfony\Component\DependencyInjection\Container;

class SwagImportExportProfileService
{
    /**
     * @var ModelManager
     */
    protected $entityManager;

    /**
     * @param Container $container
     */
    public function __construct(Container $container)
    {
        // Force loading the SwagImportExport plugin by requesting one of its services. Unfortunately, this is necessary
        // because SwagImportExport does not subscribe to onStartDispatch, so it's not guaranteed that its namespaces
        // are available when plugin updates are performed.
        // Note that the service name changed in SwagImportExport plugin version 2.x to 3.0.0.
        $swagImportExportVersion2ServiceName = 'swag_import_export.profile_service';
        $swagImportExportVersion3ServiceName = 'SwagImportExport\\Components\\Service\\ProfileService';
        if ($container->has($swagImportExportVersion2ServiceName)) {
            $container->get($swagImportExportVersion2ServiceName);
        } elseif ($container->has($swagImportExportVersion3ServiceName)) {
            $container->get($swagImportExportVersion3ServiceName);
        } else {
            throw new Exception(sprintf(
                'Cannot construct SwagImportExportProfileService. Neither SwagImportExport service "%s" nor "%s" was found.',
                $swagImportExportVersion2ServiceName,
                $swagImportExportVersion3ServiceName
            ));
        }

        $this->entityManager = $container->get('models');
    }

    /**
     * Installs any custom profiles that are not already in the database.
     *
     * @param array $profiles
     * @param string $profileTreeDirectory
     */
    public function installNewProfiles($profiles, $profileTreeDirectory)
    {
        // Note that the profile class namespace changed in SwagImportExport plugin version 2.x to 3.0.0.
        if (class_exists(SwagImportExportVersion2Profile::class)) {
            $profileClass = SwagImportExportVersion2Profile::class;
        } elseif (class_exists(SwagImportExportVersion3Profile::class)) {
            $profileClass = SwagImportExportVersion3Profile::class;
        } else {
            throw new Exception(sprintf(
                'Cannot install profiles. Neither SwagImportExport profile class "%s" nor "%s" was found.',
                SwagImportExportVersion2Profile::class,
                SwagImportExportVersion3Profile::class
            ));
        }
        $repository = $this->entityManager->getRepository($profileClass);
        $newProfiles = [];
        foreach ($profiles as $name => $type) {
            // Try to find the profile
            $profile = $repository->findOneBy([
                'name' => $name,
            ]);
            if ($profile) {
                continue;
            }

            // Create a new profile
            /** @var SwagImportExportVersion2Profile|SwagImportExportVersion3Profile $profile */
            $profile = new $profileClass();
            $profile->setName($name);
            // Set 'default' to prevent users from deleting the profile
            $profile->setDefault(true);
            $this->updateProfile($profile, $type, $profileTreeDirectory);

            $this->entityManager->persist($profile);
            $newProfiles[] = $profile;
        }

        // Save new profiles if any were added
        if (count($newProfiles) > 0) {
            $this->entityManager->flush($newProfiles);
        }
    }

    /**
     * Updates all existing custom profiles.
     *
     * @param array $profiles
     * @param string $profileTreeDirectory
     * @return array
     */
    public function updateExistingProfiles($profiles, $profileTreeDirectory)
    {
        // Make sure all custom profiles are up to date
        $repository = $this->getSwagImportExportProfileRepository();
        $updatedProfiles = [];
        foreach ($profiles as $name => $type) {
            /** @var SwagImportExportVersion2Profile|SwagImportExportVersion3Profile $profile */
            $profile = $repository->findOneBy([
                'name' => $name,
            ]);
            if (!$profile) {
                continue;
            }

            $this->updateProfile($profile, $type, $profileTreeDirectory);
            $updatedProfiles[] = $profile;
        }

        // Save changes if any were updated
        if (count($updatedProfiles) > 0) {
            $this->entityManager->flush($updatedProfiles);
        }

        return $updatedProfiles;
    }

    /**
     * Updates the $type of the given $profile, loads its respective configuration file and saves it in the profile.
     *
     * @param SwagImportExportVersion2Profile|SwagImportExportVersion3Profile $profile
     * @param string $type
     * @param string $profileTreeDirectory
     */
    protected function updateProfile($profile, $type, $profileTreeDirectory)
    {
        $profile->setType($type);
        $treePath = $profileTreeDirectory . $profile->getName() . '.json';
        if (file_exists($treePath)) {
            $tree = file_get_contents($treePath);
            $tree = preg_replace('/\\s+/', '', $tree);
            $profile->setTree($tree);
        }
    }

    private function getSwagImportExportProfileRepository()
    {
        if (class_exists(SwagImportExportVersion2Profile::class)) {
            $profileClass = SwagImportExportVersion2Profile::class;
        } elseif (class_exists(SwagImportExportVersion3Profile::class)) {
            $profileClass = SwagImportExportVersion3Profile::class;
        } else {
            throw new Exception(sprintf(
                'Neither SwagImportExport profile class "%s" now "%s" was found.',
                SwagImportExportVersion2Profile::class,
                SwagImportExportVersion3Profile::class
            ));
        }

        return $this->entityManager->getRepository($profileClass);
    }
}
