<?php

namespace AppBundle\Command;

use AppBundle\Entity\User;
use AppBundle\Enum\UserJobEngineer;
use AppBundle\Enum\UserJobEngineerCategory;
use AppBundle\Enum\UserJobTeacher;
use AppBundle\Enum\UserJobTeacherCategory;
use AppBundle\Enum\UserType;
use AppBundle\Translation\ConstTranslator;
use Doctrine\ORM\EntityManagerInterface;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Bundle\FrameworkBundle\Command\ContainerAwareCommand;
use Symfony\Component\Console\Helper\ProgressBar;
use Symfony\Component\Console\Input\InputArgument;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Input\InputOption;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Stopwatch\Stopwatch;
use Symfony\Component\Validator\Validator\ValidatorInterface;

/**
 * Update the filenames of the Content 'article' property according to the medias filenames.
 * @author Dimitri KURC <technique@agencehpj.fr>
 */
class UpdateUserJobCommand extends ContainerAwareCommand
{
    /**
     * User manager.
     *
     * @var UserManagerInterface
     */
    private $userManager;

    private $jobsEngineerCategories;
    private $jobsEngineer;
    private $jobsTeacherCategories;
    private $jobsTeacher;

    /**
     * Constructor.
     *
     * @param string|null $name The name of the command; passing null means it must be set in configure()
     * @param UserManagerInterface     $userManager
     * @param ConstTranslator     $utils
     */
    public function __construct($name = null, UserManagerInterface $userManager, ConstTranslator $utils)
    {
        $this->userManager = $userManager;

        $this->jobsEngineerCategories = $utils->trans(UserJobEngineerCategory::class);
        $this->jobsEngineer = $utils->trans(UserJobEngineer::class);
        $this->jobsTeacherCategories = $utils->trans(UserJobTeacherCategory::class);
        $this->jobsTeacher = $utils->trans(UserJobTeacher::class);

        parent::__construct($name);
    }
    
    /**
     * Configuration
     */
    protected function configure()
    {
        $this
            ->setName('cgenial:migrations:userjob')
            ->setDescription("Update the job value")
            ->addArgument('max', InputArgument::REQUIRED, 'Maximum number of users that you want. Set it to 0 if you want to include every users.');
    }

    /**
     *
     * @param InputInterface $input
     * @param OutputInterface $output
     * @throws \Doctrine\ORM\ORMException
     * @throws \Doctrine\ORM\OptimisticLockException
     */
    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $em = $this->getContainer()->get("doctrine.orm.entity_manager");

        $users = $this->findUsers($em, $input->getArgument('max'));

        // Create a new progress bar
        $progress = new ProgressBar($output, count($users));

        // Start and displays the progress bar
        $progress->start();

        foreach ($users as $user) {
            // Init vars
            $userType = $user->getType();

            if ($userType == UserType::TEACHER) {
                $listCategory = $this->jobsTeacherCategories;
                $listJobs = $this->jobsTeacher;
                $defaultJobCategory = UserJobTeacherCategory::TEACHER;
                $defaultJob = UserJobTeacher::OTHER;
            }
            else {
                $listCategory = $this->jobsEngineerCategories;
                $listJobs = $this->jobsEngineer;
                $defaultJobCategory = null;
                $defaultJob = UserJobEngineer::ENGINEER;
            }
            
            // Get old data
            $old_jobCategory = $user->getCategoryJob();
            $old_job = $user->getJob();
            $old_jobOther = $user->getJobOther();

            if(empty($old_job)) {
                $old_job = $user->getJobOther();
            }

            if(
                !empty($old_job) 
                && ((
                    // If $old_jobCategory is setted => loop is already passed (Teacher Only)
                    $userType == UserType::TEACHER
                    && empty($old_jobCategory)
                    ) || (
                    $userType == UserType::ENGINEER
                    && (
                        empty($old_job)
                        || empty($old_jobOther)
                    )
                ))
            ) {
                // Legacy - Change ʼ to '
                $old_job = str_replace('ʼ', '\'', $old_job);

                $jobCategory = $defaultJobCategory;
                $job = $defaultJob;
                $jobOther = null;
                $in_array = false;

                //Set Job
                foreach ($listJobs as $key => $j) {
                    //Try to eliminate writing differences
                    $j = str_replace(array(' et ', ' ', '/', '-', '&', 'é'), '', mb_strtolower($j));
                    $tmp = str_replace(array(' et ', ' ', '/', '-', '&', 'é'), '', mb_strtolower($old_job));

                    if (
                        strstr($j, $tmp)
                        || mb_strtolower($old_job) === mb_strtolower($key) // If loop is already passed
                    ) {
                        $in_array = true;
                        $job = $key;
                        break;
                    }
                }

                //Set JobOther if necessary
                if (!$in_array) {
                    $jobOther = mb_strtolower($old_job);
                    $jobOther = mb_strtoupper(mb_substr($jobOther,0,1)).mb_substr($jobOther,1); // Simulate mb_ucfirst()
                }
                elseif (!empty($old_jobOther)) {
                    // No losss legacy data
                    $jobOther = $old_jobOther;
                }

                //Set Job Category
                $tmp = explode('_', $job);
                // Test by key
                if (array_key_exists($tmp[0], $listCategory)) {
                    $jobCategory = $tmp[0];    
                }

                //@TMP Debug
                // $output->writeln($job . ' ' . $jobOther . ' || ' . $old_job);

                $user->setCategoryJob($jobCategory);
                $user->setJob($job);
                $user->setJobOther($jobOther);

                $this->userManager->updateUser($user);
            }

            $progress->advance();
        }

        $em->flush();

        // Ensure that the progress bar is at 100%
        $progress->finish();
    }

    /**
     * 
     * @param EntityManagerInterface $em
     * @param ValidatorInterface $validator
     * @param int $max
     * @param bool $force
     * @return array List of users
     */
    private function findUsers(
        EntityManagerInterface $em,
        int $max = 0
    ): array {
        $qb = $em->createQueryBuilder();

        // Find users from the database where the personal address or zipcode is set
        $qb->select('u')
            ->from(User::class, 'u')
            ->where('(u.job IS NOT NULL OR u.jobOther IS NOT NULL)');

        if ($max > 0) {
            $qb->setMaxResults($max);
        }

        $jobList = array_merge(UserJobTeacher::getConstants(), UserJobEngineer::getConstants());
        
        if (!empty($jobList)) {
            $qb->andWhere('u.job NOT IN (:u_job)')
                ->setParameter('u_job', array_values($jobList));
        }

        //@TMP Debug
        // $qb->andWhere('u.id = 10284'); // Teacher
        // $qb->andWhere('u.id = 7834'); // Engineer

        $users = $qb->getQuery()->getResult();
        
        return $users;
    }
}
