<?php

namespace Ignite\Core\Models\Options;

use Ignite\Core\Contracts\Source;
use Ignite\Core\Contracts\Entities\User;
use Illuminate\Database\Eloquent\Model;

class UserStates implements Source
{
    /**
     * @var Model|null
     */
    private $model;

    /**
     * UserStates constructor.
     *
     * @param Model|null $model
     */
    public function __construct(Model $model = null)
    {
        $this->model = $model;
    }

    /**
     * The source as a key-value pair array with the value as the key and the label as the value.
     *
     * @return array
     */
    public function toDropdown()
    {
        // If we have a logged-in user, get the states for the participant's country.
        $country = (func_num_args() > 0) ? func_get_arg(0) : null;
        if ($this->model instanceof Model && $country) {
            return $this->getStatesInstanceByModel($country)->toDropdown();
        }

        // If we have a logged-in user, get the states for the participant's country.
        /** @var User $user */
        if ($user = auth()->user()) {
            return $this->getStatesInstanceByUser($user)->toDropdown();
        }

        // Or fallback to the default country states
        return $this->getDefaultStatesInstance()->toDropdown();
    }

    /**
     * The states options for the given user depending on the given model.
     *
     * @param string $country
     *
     * @return Source
     */
    protected function getStatesInstanceByModel($country)
    {
        return app($this->getClassByCountry($this->model->getAttribute($country)));
    }

    /**
     * The states options for the given user depending on their country.
     *
     * @param User $user
     *
     * @return Source
     */
    protected function getStatesInstanceByUser(User $user)
    {
        return app($this->getClassByCountry($user->participant->country));
    }

    /**
     * The fully qualified class name of the source data.
     *
     * @param string $country
     *
     * @return string
     */
    protected function getClassByCountry($country)
    {
        $map = $this->getStatesMap();

        if (array_key_exists($country, $map)) {
            return $map[$country];
        }

        return NullOptions::class;
    }

    /**
     * The default states options.
     *
     * @return Source
     */
    protected function getDefaultStatesInstance()
    {
        return app($this->getDefaultStates());
    }

    /**
     * the fully qualified class name for the default states.
     *
     * @return string
     */
    protected function getDefaultStates()
    {
        return config('core.participant.states.default', States::class);
    }

    /**
     * The array map of key-value pairs containing country code to fully qualified class name.
     *
     * @param array $default
     *
     * @return array
     */
    protected function getStatesMap(array $default = [])
    {
        return config('core.participant.states.map', $default);
    }
}
