<?php

namespace App\Service;

use App\Entity\Task;
use App\Entity\TaskSchema;
use App\Enum\TaskStatus;
use App\Repository\TaskSchemaRepository;
use Doctrine\ORM\EntityManagerInterface;

class TaskGenerator
{
    public function __construct(
        private EntityManagerInterface $em,
        private TaskSchemaRepository $schemaRepo,
    ) {
    }

    public function generateNewTasks(): void
    {
        $schemas = $this->schemaRepo->findActiveWithRepeat();

        foreach ($schemas as $schema) {
            $this->removeTasks($schema);
            $this->generateTasks($schema);
        }

        $this->em->flush();
    }

    public function removeTasks(TaskSchema $schema): void
    {
        foreach ($schema->getTasks() as $task) {
            if ($task->getStatus() === TaskStatus::Past) continue;
            $this->em->remove($task);
        }
    }

    public function generateTasks(TaskSchema $schema): void
    {
        $dates = $this->getDates($schema);

        foreach ($dates as $date) {
            $task = new Task();
            $task->setName($schema->getName());
            $task->setDate($date);
            $task->setStatus($schema->getTaskStatus());
            $task->setSchema($schema);
            $this->em->persist($task);
        }
    }

    /** @return array{\DateTimeImmutable, \DateTimeImmutable} */
    private function getDateRange(TaskSchema $schema): array
    {
        $today = new \DateTimeImmutable('today');
        $from = max($today, $schema->getStart() ?? $today);
        $end = min($today->modify('+14 days'), $schema->getEnd() ?? $today->modify('+14 days'));

        return [$from, $end];
    }

    /** @return list<\DateTimeImmutable> */
    private function getDates(TaskSchema $schema): array
    {
        [$from, $end] = $this->getDateRange($schema);
        $type = $schema->getRepeatType();
        $repeat = $schema->getRepeat();

        $dates = [];
        for ($date = $from; $date <= $end; $date = $date->modify('+1 day')) {

            if ($type === 'weekly') {
                $weekday = (int) $date->format('N') - 1;
                if(!$repeat['weekly'][$weekday]) continue;
            }
            if ($type === 'monthly') {
                $monthday = (int) $date->format('j') - 1;
                if(!$repeat['monthly'][$monthday]) continue;
            }

            $dates[] = $date;
        }

        return $dates;
    }
}
