<?php

declare(strict_types=1);

/*
 * This file is part of the Sonata Project package.
 *
 * (c) Thomas Rabaix <thomas.rabaix@sonata-project.org>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

namespace App\Exporter;

use App\Entity\Adherent;
use App\Entity\Prestataire;
use App\Entity\Flux;
use App\Entity\ExternalAdherentDatedData;
use App\Entity\GlobalParameter;
use App\Utils\CotisationUtils;
use Doctrine\ORM\EntityManagerInterface;
use Doctrine\ORM\Query;
use Sonata\Exporter\Source\AbstractPropertySourceIterator;
use Sonata\Exporter\Source\SourceIteratorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;

/**
 * @final since sonata-project/exporter 2.4.
 */
class CustomDoctrineORMQuerySourceIterator extends AbstractPropertySourceIterator implements SourceIteratorInterface
{
    /**
     * @var Query
     */
    protected $query;
    protected $em;
    protected $cotisationUtils;
    protected $container;

    /**
     * @param array<string> $fields Fields to export
     */
    public function __construct(
        CotisationUtils $cotisationUtils,
        EntityManagerInterface $em,
        ContainerInterface $container,
        Query $query,
        array $fields,
        string $dateTimeFormat = 'r'
    ) {
        $this->em = $em;
        $this->cotisationUtils = $cotisationUtils;
        $this->container = $container;
        $this->query = clone $query;
        $this->query->setParameters($query->getParameters());
        foreach ($query->getHints() as $name => $value) {
            $this->query->setHint($name, $value);
        }

        parent::__construct($fields, $dateTimeFormat);
    }

    public function current()
    {
        $current = $this->iterator->current();

        $data = $this->getCurrentData($current[0]);

        // Add for kohinos
        if (!empty($data['Id']) && !empty($data['Raison'])) {
            //presta
            $presta = $this->em->getRepository(Prestataire::class)->findOneById($data['Id']);
            $gestionnaires = [];
            $users = $presta->getUsers();
            foreach ($users as $user) {
                $gestionnaires[] = $user->getLastname() . ' ' . $user->getFirstname() . ' (' . $user->getEmail() . ')';
            }
            $data['Gestionnaires'] = implode(' - ', $gestionnaires);
            $cotisEnd = $this->cotisationUtils->isCotisationValidForPresta($presta);
            $cotisEnd = is_string($cotisEnd) ? new \DateTime( $cotisEnd ) : $cotisEnd;
            $data['Cotisation à jour'] = false == $cotisEnd ? '' : ($cotisEnd->format('d/m/Y'));
            $firstCotis = $this->cotisationUtils->getFirstCotisationForPresta($presta);
            $firstCotis = is_string($firstCotis) ? new \DateTime( $firstCotis ) : $firstCotis;
            $data['Première Cotisation'] = false == $firstCotis ? '' : ($firstCotis->format('d/m/Y'));
            if ($this->container->getParameter('tav_env')) {
                $adresses = [];
                foreach ($presta->getGeolocs() as $geoloc) {
                    $adresses[] = $geoloc ? $geoloc->getFullAddresse() : "";
                }
                $data['Adresses'] = implode(' - ', $adresses);
            }
        } elseif (!empty($data['Id']) && !empty($data['Email'])) {
            //adherent
            $adherent = $this->em->getRepository(Adherent::class)->findOneById($data['Id']);

            if ($this->container->getParameter('tav_env')) {
                // Last TAV cotisation
                $cotisations = $this->em->getRepository(Flux::class)->getLastTavCotisation($adherent);
                if (count($cotisations) > 0) {
                    $cotisDate = date("d/m/Y H:i:s", strtotime($cotisations[0]["created_at"]));
                    $data['Dernière Cotisation'] = $cotisDate;
                } else {
                    $data['Dernière Cotisation'] = "Aucune";
                }

                // Current emlc balance
                $balance = $adherent->getEmlcAccount()->getBalance();
                $mlc = $this->em->getRepository(GlobalParameter::class)->val(GlobalParameter::MLC_SYMBOL);
                $data['Solde'] = $balance . " " . $mlc;

                // Profil de cotisation
                $cotisationProfile = $adherent->getProfilDeCotisation();
                if (!is_null($cotisationProfile) ) {
                    $data['Profil de cotisation'] = $cotisationProfile;
                } else {
                    $data['Profil de cotisation'] = "Aucun profil assigné";
                }
                if ($this->container->getParameter('ccas_mode')) {
                    $data['Numéro d\'anonymisation'] = $adherent->getAnonymousToken();
                }
                $data["Adresse"] = (string) ($adherent->getGeoloc() ?: '');

                if ($this->container->getParameter('use_external_data')) {
                    // Add external data if exists
                    $ext_data = $adherent->getExternalData();
                    $data["Cohorte"] = $ext_data ? $ext_data->getCohort() : "";
                    $data["ID externe"] = $ext_data ? $ext_data->getExternalId() : "";

                    // Add external dated data if exists
                    $ext_dated_data = $adherent->getExternalDatedDataCollection();

                    /**
                     * If some line have an attribute and others don't, it won't be displayed.
                     * So we need to make sure every line in the file as [maxDatedDataCount] columns of dated data
                     */
                    $maxDatedDataCount = $this->em->getRepository(ExternalAdherentDatedData::class)->getMaxDatedDataCount();
                    for($i = 0 ; $i < $maxDatedDataCount; $i++) {
                        $yearCount = $i+1;
                        if ($ext_dated_data[$i]) {
                            $data["Année $yearCount"] = $ext_dated_data[$i]->getYear();
                            $data["Revenu mensuel $yearCount"] = $ext_dated_data[$i]->getMonthlyIncome();
                            $data["Revenu annuel $yearCount"] = $ext_dated_data[$i]->getAnnualIncome();
                        } else {
                            $data["Année $yearCount"] = "";
                            $data["Revenu mensuel $yearCount"] = "";
                            $data["Revenu annuel $yearCount"] = "";
                        }
                    }
                }
            } else {
                $cotisEnd = $this->cotisationUtils->isCotisationValidForAdherent($adherent);
                $cotisEnd = is_string($cotisEnd) ? new \DateTime( $cotisEnd ) : $cotisEnd;
                $data['Cotisation à jour'] = false == $cotisEnd ? '' : ($cotisEnd->format('d/m/Y'));
                $firstCotis = $this->cotisationUtils->getFirstCotisationForAdherent($adherent);
                $firstCotis = is_string($firstCotis) ? new \DateTime( $firstCotis ) : $firstCotis;
                $data['Première Cotisation'] = false == $firstCotis ? '' : ($firstCotis->format('d/m/Y'));
            }
            $adminRoles = '';
            if (!empty($adherent->getUser())) {
                foreach ($adherent->getUser()->getPossiblegroups() as $group) {
                    if (!empty($adminRoles)) {
                        $adminRoles .= ', ';
                    }
                    $adminRoles .= $group->getName();
                    if ('Comptoir' == $group->getName()) {
                        $adminRoles .= '(' . implode(',', $adherent->getUser()->getComptoirsgeres()->toArray()) . ')';
                    } elseif ('Prestataire' == $group->getName()) {
                        $adminRoles .= '(' . implode(',', $adherent->getUser()->getPrestataires()->toArray()) . ')';
                    } elseif ('Caissier' == $group->getName()) {
                        $adminRoles .= '(' . implode(',', $adherent->getUser()->getCaissiers()->toArray()) . ')';
                    } elseif ('Gestionnaire de Groupe' == $group->getName() || 'Contact' == $group->getName()) {
                        $adminRoles .= '(' . implode(',', $adherent->getUser()->getGroupesgeres()->toArray()) . ')';
                    }
                }
            }
            $data["Droits d'administration"] = $adminRoles;
        }

        $this->query->getEntityManager()->clear();

        return $data;
    }

    final public function rewind(): void
    {
        $this->iterator = $this->query->iterate();
        $this->iterator->rewind();
    }
}
