<?php

namespace Ignite\Core\Models\Seeds;

use Ignite\Core\Entities\Group;
use Ignite\Core\Entities\Participant;
use Ignite\Core\Repositories\ParticipantRepository;

class ParticipantSeeder extends BaseSeeder
{
    /** @var string */
    protected $json = 'participant';

    /**
     * Seed the database table.
     *
     * @throws \Exception
     */
    public function seed()
    {
        $participants = $this->parser->parse($this->path());

        foreach ($participants as $participant) {
            $this->seedParticipant($participant);
        }
    }

    /**
     * Seed a table record.
     *
     * @param  array $participant
     * @return array
     * @throws \Exception
     */
    private function seedParticipant($participant)
    {
        $repository = app(ParticipantRepository::class);

        $group = $this->extractGroup($participant);
        
        if ($user = $this->participantExists($participant['email'])) {
            $model = $this->updateParticipant($user->user_id, $participant, $repository);
        } else {
            $model = $this->createParticipant($participant, $repository);
        }

        $this->attachToGroup($model->getKey(), $group);
        
        return $participant;
    }

    /**
     * Check if the participant exists by looking up their email.
     *
     * @param  string $email
     * @return Participant
     */
    private function participantExists($email)
    {
        return Participant::where('email', strtolower($email))->first();
    }

    /**
     * Create a participant record.
     *
     * @param  array                 $participant
     * @param  ParticipantRepository $repository
     * @return Participant
     * @throws \Exception
     */
    private function createParticipant(array $participant, ParticipantRepository $repository)
    {
        return $repository->create(compact('participant'));
    }

    /**
     * Update a participant record.
     *
     * @param  array                 $participant
     * @param  ParticipantRepository $repository
     * @return Participant
     * @throws \Exception
     */
    private function updateParticipant($userId, array $participant, ParticipantRepository $repository)
    {
        return $repository->update($userId, compact('participant'));
    }

    /**
     * Extract the group from the data, remove it from the array and return it.
     *
     * @param  array $participant
     * @return string
     */
    private function extractGroup(&$participant)
    {
        $group = $participant['group'];

        unset($participant['group']);

        return $group;
    }

    /**
     * Attach the participant to the group.
     *
     * @param  int $userId
     * @param  string $groupName
     *
     * @return Group
     */
    private function attachToGroup($userId, $groupName)
    {
        /** @var Group $group */
        $group = Group::where('name', $groupName)->first();

        $group->users()->syncWithoutDetaching([
            $userId => [
                'created_at' => now(),
                'updated_at' => now(),
            ]
        ]);

        return $group;
    }
}
