<?php

declare(strict_types=1);

namespace MauticPlugin\DealFlowBundle\Service;

use Mautic\CoreBundle\Helper\CoreParametersHelper;
use MauticPlugin\DealFlowBundle\Entity\DealContactAssociationRepository;
use MauticPlugin\DealFlowBundle\Entity\DealRepository;

class AutomationOptionsProvider
{
    public function __construct(
        private readonly DefaultPipelineInitializer $pipelineInitializer,
        private readonly DealRepository $dealRepository,
        private readonly DealContactAssociationRepository $associationRepository,
        private readonly CoreParametersHelper $coreParametersHelper,
    ) {
    }

    /**
     * @return array<string, int>
     */
    public function getPipelineChoices(): array
    {
        $choices = [];

        foreach ($this->pipelineInitializer->getActivePipelines() as $pipeline) {
            if (null === $pipeline->getId()) {
                continue;
            }

            $choices[$pipeline->getName()] = $pipeline->getId();
        }

        return $choices;
    }

    /**
     * @return array<string, array<string, int>>
     */
    public function getGroupedStageChoices(bool $activeOnly = true): array
    {
        $choices = [];

        foreach ($this->pipelineInitializer->getActivePipelines() as $pipeline) {
            $pipelineChoices = [];

            foreach ($this->pipelineInitializer->getOrderedStages($pipeline, $activeOnly) as $stage) {
                if (null === $stage->getId()) {
                    continue;
                }

                $pipelineChoices[$stage->getName()] = $stage->getId();
            }

            if ([] !== $pipelineChoices) {
                $choices[$pipeline->getName()] = $pipelineChoices;
            }
        }

        return $choices;
    }

    /**
     * @return array<string, int>
     */
    public function getFlatStageChoices(bool $activeOnly = true): array
    {
        $choices = [];

        foreach ($this->getGroupedStageChoices($activeOnly) as $pipelineName => $stageChoices) {
            foreach ($stageChoices as $stageName => $stageId) {
                $choices[$pipelineName.': '.$stageName] = $stageId;
            }
        }

        return $choices;
    }

    /**
     * @return array<string, string>
     */
    public function getStatusChoices(bool $includeAny = false): array
    {
        $choices = [];

        if ($includeAny) {
            $choices['Any status'] = '';
        }

        $choices['Open'] = 'open';
        $choices['Closed won'] = 'won';
        $choices['Closed lost'] = 'lost';

        return $choices;
    }

    /**
     * @return array<string, string>
     */
    public function getSourceChoices(?string $currentSource = null): array
    {
        $choices = [];
        $sources = [];

        foreach ($this->normalizeConfiguredList($this->coreParametersHelper->get('dealflow_default_sources', [])) as $source) {
            $source = trim((string) $source);
            if ('' !== $source) {
                $sources[$source] = true;
            }
        }

        foreach ($this->dealRepository->findDistinctSources() as $source) {
            $source = trim($source);
            if ('' !== $source) {
                $sources[$source] = true;
            }
        }

        $currentSource = trim((string) $currentSource);
        if ('' !== $currentSource) {
            $sources[$currentSource] = true;
        }

        $sourceLabels = array_keys($sources);
        natcasesort($sourceLabels);

        foreach ($sourceLabels as $sourceLabel) {
            $choices[$sourceLabel] = $sourceLabel;
        }

        return $choices;
    }

    /**
     * @return array<string, string>
     */
    public function getStakeholderRoleChoices(bool $includeAny = false): array
    {
        $choices = [];

        if ($includeAny) {
            $choices['Any stakeholder role'] = '';
        }

        $labels = [];

        foreach ($this->normalizeConfiguredList($this->coreParametersHelper->get('dealflow_default_association_labels', [])) as $label) {
            $label = trim((string) $label);
            if ('' !== $label) {
                $labels[$label] = true;
            }
        }

        foreach ($this->associationRepository->findDistinctLabels() as $label) {
            $label = trim($label);
            if ('' !== $label) {
                $labels[$label] = true;
            }
        }

        $roleLabels = array_keys($labels);
        natcasesort($roleLabels);

        foreach ($roleLabels as $roleLabel) {
            $choices[$roleLabel] = $roleLabel;
        }

        return $choices;
    }

    /**
     * @return list<string>
     */
    private function normalizeConfiguredList(mixed $value): array
    {
        if (is_array($value)) {
            $items = $value;
        } elseif (is_string($value)) {
            $decoded = json_decode($value, true);

            if (JSON_ERROR_NONE === json_last_error() && is_array($decoded)) {
                $items = $decoded;
            } else {
                $items = preg_split('/\r\n|\r|\n|,/', $value) ?: [];
            }
        } elseif ($value instanceof \Traversable) {
            $items = iterator_to_array($value, false);
        } elseif (null === $value) {
            $items = [];
        } else {
            $items = [(string) $value];
        }

        $normalized = [];

        foreach ($items as $item) {
            $label = trim((string) $item);

            if ('' !== $label) {
                $normalized[$label] = true;
            }
        }

        return array_keys($normalized);
    }
}
