<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\Config;

use Butschster\ContextGenerator\Application\FSPath;
use Butschster\ContextGenerator\Application\Logger\LoggerPrefix;
use Butschster\ContextGenerator\Config\Exception\ConfigLoaderException;
use Butschster\ContextGenerator\Config\Loader\ConfigLoaderFactoryInterface;
use Butschster\ContextGenerator\Config\Loader\ConfigLoaderInterface;
use Butschster\ContextGenerator\DirectoriesInterface;
use Psr\Log\LoggerInterface;

/**
 * Service for providing configuration loaders based on different sources
 */
final readonly class ConfigurationProvider
{
    public function __construct(
        private ConfigLoaderFactoryInterface $loaderFactory,
        private DirectoriesInterface $dirs,
        #[LoggerPrefix(prefix: 'config-provider')]
        private ?LoggerInterface $logger = null,
    ) {}

    /**
     * Get a config loader from an inline JSON string
     */
    public function fromString(string $jsonConfig): ConfigLoaderInterface
    {
        $this->logger?->info('Using inline JSON configuration');

        return $this->loaderFactory->createFromString(
            jsonConfig: $jsonConfig,
        );
    }

    /**
     * Get a config loader for a specific path (file or directory)
     */
    public function fromPath(string $configPath): ConfigLoaderInterface
    {
        $resolvedPath = $this->resolvePath($configPath);

        if ($resolvedPath->isDir()) {
            $this->logger?->info('Looking for configuration files in directory', [
                'directory' => $resolvedPath,
            ]);

            return $this->loaderFactory->create((string) $resolvedPath);
        }
        $this->logger?->info('Loading configuration from specific file', [
            'file' => $resolvedPath,
        ]);

        return $this->loaderFactory->createForFile((string) $resolvedPath);
    }

    /**
     * Get a config loader using the default paths
     */
    public function fromDefaultLocation(): ConfigLoaderInterface
    {
        $this->logger?->info('Loading configuration from default location', [
            'rootPath' => (string) $this->dirs->getConfigPath(),
        ]);

        return $this->loaderFactory->create((string) $this->dirs->getConfigPath());
    }

    /**
     * Resolve a path (absolute or relative to root path)
     */
    private function resolvePath(string $path): FSPath
    {
        $pathObj = FSPath::create($path);

        // If it's an absolute path, use it directly
        if ($pathObj->isAbsolute()) {
            $resolvedPath = $pathObj;
        } else {
            // Otherwise, resolve it relative to the root path
            $resolvedPath = $this->dirs->getRootPath()->join($path);
        }

        // Check if the path exists
        if (!$resolvedPath->exists()) {
            throw new ConfigLoaderException(\sprintf('Path not found: %s', $resolvedPath));
        }

        return $resolvedPath;
    }
}
