<?php

namespace Ignite\Core\Repositories;

use DomainException;
use Ignite\Core\Contracts\Repositories\ImportRepository as ImportRepositoryInterface;
use Ignite\Core\Entities\Import;
use Ignite\Core\Entities\User;
use Ignite\Core\Models\Import\File;
use Nwidart\Modules\Contracts\RepositoryInterface;

class ImportRepository implements ImportRepositoryInterface
{
    /**
     * Get a pre-configured Import query builder.
     *
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function query()
    {
        return Import::query();
    }

    /**
     * Find an import record by ID.
     *
     * @param int $id
     *
     * @return Import
     */
    public function find($id)
    {
        return Import::findOrFail($id);
    }

    /**
     * Paginate import records.
     *
     * @param int $records
     * @return \Illuminate\Contracts\Pagination\LengthAwarePaginator
     */
    public function paginate($records = 10)
    {
        return $this->query()->latest()->paginate($records);
    }

    /**
     * Find all active imports.
     *
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function findAll()
    {
        return $this->query()->get();
    }

    /**
     * Create a new import record.
     *
     * @param array $data
     *
     * @return Import
     */
    public function create(array $data)
    {
        if (! isset($data['type']) || empty($data['type'])) {
            throw new DomainException('The import type was not set.');
        }

        $types = $this->getAllowedTypes();
        if (! in_array($data['type'], array_keys($types))) {
            throw new DomainException(sprintf(
                'The import type `%s` is not supported.',
                $data['type'] ?? 'Unknown'
            ));
        }

        /** @var Import $import */
        $import = tap(new Import($data), function (Import $instance) {
            $instance->save();
        })->fresh();

        if (! isset($data['records'])) {
            $import->records = $import->resolveType()->count();
            $import->save();
        }

        return $import;
    }

    /**
     * Create from an import file.
     *
     * @param File $file
     * @param User|null $createdBy
     *
     * @return \Ignite\Core\Entities\Import
     */
    public function createFromFile(File $file, ?User $createdBy = null): \Ignite\Core\Entities\Import
    {
        $data = $file->toArray() + ($createdBy ? ['created_by' => $createdBy->getKey()] : []);

        return $this->create($data);
    }

    /**
     * Delete the import with the provided ID.
     *
     * @param int $id
     * @return bool
     * @throws \Exception
     */
    public function delete($id)
    {
        $import = $this->find($id);

        $import->deleteLog();
        $import->deleteFile();

        return (bool)$import->delete();
    }

    /**
     * The allowed types as a map of class => label.
     *
     * @return array
     */
    public function getAllowedTypes()
    {
        $core = collect(config()->get('core.import.types'));
        $all = array_except(config()->all(), 'core');
        $search = data_get($all, '*.import.types', []);
        $modules = collect($search)
            ->filter()
            ->flatMap(function ($type) {
                return $type;
            })
            ->filter(function ($value, $module) {
                return app(RepositoryInterface::class)->allEnabled(ucfirst(strtolower($module)));
            });

        return $core->merge($modules)->keyBy('class')->map(function ($type) {
            return $type['label'];
        })->toArray();
    }
}
