<?php

declare(strict_types=1);

namespace MauticPlugin\DealFlowBundle\Service;

use Doctrine\ORM\EntityManagerInterface;
use Mautic\CoreBundle\Helper\CoreParametersHelper;
use MauticPlugin\DealFlowBundle\Entity\DealStage;
use MauticPlugin\DealFlowBundle\Entity\DealStageRepository;
use MauticPlugin\DealFlowBundle\Entity\Pipeline;
use MauticPlugin\DealFlowBundle\Entity\PipelineRepository;

class DefaultPipelineInitializer
{
    public const DEFAULT_PIPELINE_NAME = 'Sales Pipeline';

    public function __construct(
        private readonly EntityManagerInterface $entityManager,
        private readonly PipelineRepository $pipelineRepository,
        private readonly DealStageRepository $stageRepository,
        private readonly CoreParametersHelper $coreParametersHelper,
    ) {
    }

    public function ensureDefaultPipeline(): Pipeline
    {
        $pipeline = $this->pipelineRepository->findMarkedDefaultPipeline();
        if (!$pipeline instanceof Pipeline) {
            $pipeline = $this->pipelineRepository->findDefaultPipeline();
        }

        if (!$pipeline instanceof Pipeline) {
            $pipeline = new Pipeline();
            $pipeline->setName(self::DEFAULT_PIPELINE_NAME);
            $this->entityManager->persist($pipeline);
            $this->entityManager->flush();
        }

        if ('' === trim($pipeline->getName()) || 'Deal Flow' === $pipeline->getName()) {
            $pipeline->setName(self::DEFAULT_PIPELINE_NAME);
        }

        if (!$pipeline->isDefault()) {
            $pipeline->setIsDefault(true);
        }

        if (!$pipeline->isPublished()) {
            $pipeline->setIsPublished(true);
        }

        $pipeline->setDateModified(new \DateTime());
        $this->entityManager->flush();
        $this->pipelineRepository->clearDefaultFlag($pipeline->getId());

        $this->ensureStages($pipeline);

        return $pipeline;
    }

    /**
     * @return list<Pipeline>
     */
    public function getActivePipelines(): array
    {
        $defaultPipeline = $this->ensureDefaultPipeline();
        $pipelines = $this->pipelineRepository->findActivePipelines();

        if ([] === $pipelines) {
            return [$defaultPipeline];
        }

        foreach ($pipelines as $pipeline) {
            $this->ensureStages($pipeline);
        }

        return $pipelines;
    }

    public function resolvePipeline(?int $pipelineId = null): Pipeline
    {
        if (null !== $pipelineId && $pipelineId > 0) {
            $pipeline = $this->pipelineRepository->find($pipelineId);
            if ($pipeline instanceof Pipeline && $pipeline->isPublished()) {
                $this->ensureStages($pipeline);

                return $pipeline;
            }
        }

        return $this->ensureDefaultPipeline();
    }

    /**
     * @return list<DealStage>
     */
    public function getOrderedStages(Pipeline $pipeline, bool $activeOnly = false): array
    {
        $this->ensureStages($pipeline);

        return $this->stageRepository->findByPipelineOrdered($pipeline, $activeOnly);
    }

    public function getFirstStage(Pipeline $pipeline): ?DealStage
    {
        $this->ensureStages($pipeline);

        return $this->stageRepository->findFirstStageForPipeline($pipeline);
    }

    public function ensureStages(Pipeline $pipeline): void
    {
        if ([] !== $this->stageRepository->findByPipelineOrdered($pipeline)) {
            return;
        }

        $seed = $this->coreParametersHelper->get('dealflow_default_stage_seed');
        $sort = 10;
        foreach ($seed as $definition) {
            $stage = new DealStage();
            $stage->setPipeline($pipeline)
                ->setName((string) $definition['name'])
                ->setSlug($this->slugify((string) $definition['name']))
                ->setSortOrder($sort)
                ->setProbability((int) ($definition['probability'] ?? 0))
                ->setStageType((string) $definition['stage_type'])
                ->setIsPublished(true);

            $this->entityManager->persist($stage);
            $sort += 10;
        }

        $this->entityManager->flush();
    }

    public function slugify(string $value): string
    {
        $value = strtolower(trim($value));
        $value = preg_replace('/[^a-z0-9]+/', '-', $value) ?? '';
        $value = trim($value, '-');

        return '' === $value ? 'stage' : $value;
    }
}
