<?php

declare(strict_types=1);

namespace MauticPlugin\DealFlowBundle\ViewModel;

use Symfony\Component\DependencyInjection\Attribute\Exclude;

/**
 * Plain view model for the pipeline kanban page.
 * Encapsulates computed aggregation logic that was previously inline in Twig.
 * No service dependencies — constructor takes pipeline column data.
 *
 * #[Exclude] prevents Symfony's service auto-registration from treating this
 * value object as a service. It is always instantiated directly: new PipelineViewModel($columns).
 */
#[Exclude]
final class PipelineViewModel
{
    private int $openDealCount = 0;
    private float $openDealValue = 0.0;
    private float $wonDealValue = 0.0;

    /**
     * @param array<int, array{stage: \MauticPlugin\DealFlowBundle\Entity\DealStage, deals: array<int, \MauticPlugin\DealFlowBundle\Entity\Deal>}> $columns
     */
    public function __construct(
        private readonly array $columns,
    ) {
        $this->computeStats();
    }

    public function getOpenDealCount(): int
    {
        return $this->openDealCount;
    }

    public function getOpenDealValue(): float
    {
        return $this->openDealValue;
    }

    public function getWonDealValue(): float
    {
        return $this->wonDealValue;
    }

    /**
     * Average value of open deals. Returns 0 if no open deals.
     */
    public function getAverageDealValue(): float
    {
        if (0 === $this->openDealCount) {
            return 0.0;
        }

        return $this->openDealValue / $this->openDealCount;
    }

    /**
     * Total value across ALL pipeline deals (open + won + lost).
     */
    public function getTotalValue(): float
    {
        $total = 0.0;
        foreach ($this->columns as $column) {
            foreach ($column['deals'] as $deal) {
                $total += (float) ($deal->getAmount() ?? 0);
            }
        }

        return $total;
    }

    /**
     * Distribution of deals by stage type.
     *
     * @return array<string, int> stage type => deal count
     */
    public function getStageDistribution(): array
    {
        $distribution = [];
        foreach ($this->columns as $column) {
            $type = $column['stage']->getStageType();
            if (!isset($distribution[$type])) {
                $distribution[$type] = 0;
            }
            $distribution[$type] += \count($column['deals']);
        }

        return $distribution;
    }

    /**
     * Win rate: won deals / (won + lost). Returns null if no won or lost deals.
     */
    public function getWinRate(): ?float
    {
        $won = 0;
        $lost = 0;
        foreach ($this->columns as $column) {
            $type = $column['stage']->getStageType();
            $count = \count($column['deals']);
            if ('won' === $type) {
                $won += $count;
            } elseif ('lost' === $type) {
                $lost += $count;
            }
        }

        $total = $won + $lost;
        if (0 === $total) {
            return null;
        }

        return $won / $total;
    }

    /**
     * Value total for a single stage column.
     *
     * @param array<int, \MauticPlugin\DealFlowBundle\Entity\Deal> $deals
     */
    public function getStageTotal(array $deals): float
    {
        $total = 0.0;
        foreach ($deals as $deal) {
            $total += (float) ($deal->getAmount() ?? 0);
        }

        return $total;
    }

    private function computeStats(): void
    {
        foreach ($this->columns as $column) {
            $stageType = $column['stage']->getStageType();
            foreach ($column['deals'] as $deal) {
                $amount = (float) ($deal->getAmount() ?? 0);
                if ('open' === $stageType) {
                    ++$this->openDealCount;
                    $this->openDealValue += $amount;
                } elseif ('won' === $stageType) {
                    $this->wonDealValue += $amount;
                }
            }
        }
    }
}
