<?php

declare(strict_types=1);

/*
 * Chill is a software for social workers
 *
 * For the full copyright and license information, please view
 * the LICENSE file that was distributed with this source code.
 */

namespace Chill\PersonBundle\Service\SocialWork;

use Chill\PersonBundle\Entity\SocialWork\Evaluation;
use Chill\PersonBundle\Entity\SocialWork\Goal;
use Chill\PersonBundle\Entity\SocialWork\Result;
use Chill\PersonBundle\Entity\SocialWork\SocialAction;
use Chill\PersonBundle\Templating\Entity\SocialActionRender;
use Chill\PersonBundle\Templating\Entity\SocialIssueRender;
use Chill\MainBundle\Templating\TranslatableStringHelperInterface;
use League\Csv\Writer;
use Symfony\Contracts\Translation\TranslatorInterface;

final readonly class SocialActionCSVExportService
{
    public function __construct(
        private SocialIssueRender $socialIssueRender,
        private SocialActionRender $socialActionRender,
        private TranslatableStringHelperInterface $stringHelper,
        private TranslatorInterface $translator,
    ) {}

    public function generateCsv(array $actions): Writer
    {
        // CSV headers
        $headers = array_map(
            fn (string $tr) => $this->translator->trans('export.social_action_list.'.$tr),
            array_keys($this->formatRow(new SocialAction()))
        );

        $csv = Writer::from('php://temp', 'w+');
        $csv->insertOne($headers);

        foreach ($actions as $action) {
            $hasGoals = !$action->getGoals()->isEmpty();
            $hasResults = !$action->getResults()->isEmpty();
            $hasEvaluations = !$action->getEvaluations()->isEmpty();

            // If action has no goals, results, or evaluations, insert a single row
            if (!$hasGoals && !$hasResults && !$hasEvaluations) {
                $csv->insertOne($this->formatRow($action));
                continue;
            }

            // Process goals and their results
            if ($hasGoals) {
                foreach ($action->getGoals() as $goal) {
                    if ($goal->getResults()->isEmpty()) {
                        $csv->insertOne($this->formatRow($action, $goal));
                    } else {
                        foreach ($goal->getResults() as $goalResult) {
                            $csv->insertOne($this->formatRow($action, $goal, $goalResult));
                        }
                    }
                }
            }

            // Process results that are linked to this action (regardless of whether they have goals elsewhere)
            if ($hasResults && !$hasGoals) {
                foreach ($action->getResults() as $result) {
                    $csv->insertOne($this->formatRow($action, null, null, $result));
                }
            }

            // Process evaluations
            if ($hasEvaluations) {
                foreach ($action->getEvaluations() as $evaluation) {
                    $csv->insertOne($this->formatRow($action, evaluation: $evaluation));
                }
            }
        }

        return $csv;
    }

    private function formatRow(
        SocialAction $action,
        ?Goal $goal = null,
        ?Result $goalResult = null,
        ?Result $resultWithoutGoal = null,
        ?Evaluation $evaluation = null,
    ): array {
        return [
            'action_id' => $action->getId(),
            'social_issue_id' => $action->getIssue()?->getId(),
            'problematique_label' => null !== $action->getIssue() ? $this->socialIssueRender->renderString($action->getIssue(), []) : null,
            'desactivation_date' => $action->getDesactivationDate()?->format('Y-m-d'),
            'social_issue_ordering' => $action->getIssue()?->getOrdering(),
            'action_label' => $this->socialActionRender->renderString($action, []),
            'action_ordering' => $action->getOrdering(),
            'goal_label' => null !== $goal ? $this->stringHelper->localize($goal->getTitle()) : null,
            'goal_id' => $goal?->getId(),
            'goal_result_label' => null !== $goalResult ? $this->stringHelper->localize($goalResult->getTitle()) : null,
            'goal_result_id' => $goalResult?->getId(),
            'result_without_goal_label' => null !== $resultWithoutGoal ? $this->stringHelper->localize($resultWithoutGoal->getTitle()) : null,
            'result_without_goal_id' => $resultWithoutGoal?->getId(),
            'evaluation_title' => null !== $evaluation ? $this->stringHelper->localize($evaluation->getTitle()) : null,
            'evaluation_id' => $evaluation?->getId(),
            'evaluation_url' => $evaluation?->getUrl(),
            'evaluation_delay_month' => $evaluation?->getDelay()?->format('%m'),
            'evaluation_delay_week' => $evaluation?->getDelay()?->format('%w'),
            'evaluation_delay_day' => $evaluation?->getDelay()?->format('%d'),
        ];
    }
}
