<?php

declare(strict_types=1);

/*
 * This file is a part of the DiscordPHP project.
 *
 * Copyright (c) 2015-present David Cole <david.cole1340@gmail.com>
 *
 * This file is subject to the MIT license that is bundled
 * with this source code in the LICENSE.md file.
 */

namespace Discord\Factory;

use Discord\Discord;
use Discord\Parts\Part;
use Discord\Repository\AbstractRepository;

/**
 * Exposes an interface to build part objects without the other requirements.
 *
 * @since 4.0.0
 */
class Factory
{
    /**
     * The Discord client.
     *
     * @var Discord Client.
     */
    protected $discord;

    /**
     * Constructs a factory.
     *
     * @param Discord $discord The Discord client.
     */
    public function __construct(Discord $discord)
    {
        $this->discord = $discord;
    }

    /**
     * Creates an object.
     *
     * @param string $class   The class to build.
     * @param mixed  $data    Data to create the object.
     * @param bool   $created Whether the object is created (if part).
     *
     * @return Part|AbstractRepository The object.
     * @throws \Exception
     *
     * @deprecated 10.37.4 Use `Factory::part()` or `Factory::repository()`
     */
    public function create(string $class, $data = [], bool $created = false)
    {
        if (! is_array($data)) {
            $data = (array) $data;
        }

        if (is_subclass_of($class, Part::class)) {
            $object = $this->part($class, $data, $created);
        } elseif (is_subclass_of($class, AbstractRepository::class)) {
            $object = $this->repository($class, $data);
        } elseif (strpos($class, 'Discord\\Parts') !== false) {
            $object = $this->part($class, $data, $created);
        } elseif (strpos($class, 'Discord\\Repository') !== false) {
            $object = $this->repository($class, $data);
        } else {
            throw new \Exception('The class '.$class.' is not a Part or a Repository.');
        }

        return $object;
    }

    /**
     * Creates a part.
     *
     * @param string $class   The class to build.
     * @param array  $data    Data to create the object.
     * @param bool   $created Whether the object is created (if part).
     *
     * @return Part The part.
     */
    public function part(string $class, array $data = [], bool $created = false): Part
    {
        return new $class($this->discord, $data, $created);
    }

    /**
     * Creates a repository.
     *
     * @param string $class The class to build.
     * @param array  $data  Data to create the object.
     *
     * @return AbstractRepository The repository.
     */
    public function repository(string $class, array $data = []): AbstractRepository
    {
        return new $class($this->discord, $data);
    }
}
