<?php

declare(strict_types=1);

namespace Butschster\ContextGenerator\Source\Composer\Package;

/**
 * Value object to hold information about a Composer package
 */
final readonly class ComposerPackageInfo
{
    /**
     * @param string $name The package name
     * @param string $path The package path in the filesystem
     * @param string $version The package version
     * @param array<string, mixed> $composerConfig The package's composer.json contents
     */
    public function __construct(
        public string $name,
        public string $path,
        public string $version,
        public array $composerConfig = [],
    ) {}

    /**
     * Get the package description
     */
    public function getDescription(): string
    {
        return $this->composerConfig['description'] ?? '';
    }

    /**
     * Get the package authors
     *
     * @return array<array<string, string>>
     */
    public function getAuthors(): array
    {
        return $this->composerConfig['authors'] ?? [];
    }

    /**
     * Get formatted authors string
     */
    public function getFormattedAuthors(): string
    {
        $authors = $this->getAuthors();
        if (empty($authors)) {
            return '';
        }

        $formattedAuthors = [];
        foreach ($authors as $author) {
            $authorParts = [];
            if (isset($author['name'])) {
                $authorParts[] = $author['name'];
            }
            if (isset($author['email'])) {
                $authorParts[] = "<{$author['email']}>";
            }

            if (!empty($authorParts)) {
                $formattedAuthors[] = \implode(' ', $authorParts);
            }
        }

        return \implode(', ', $formattedAuthors);
    }

    /**
     * Get the package license
     */
    public function getLicense(): string|array
    {
        return $this->composerConfig['license'] ?? '';
    }

    /**
     * Get formatted license string
     */
    public function getFormattedLicense(): string
    {
        $license = $this->getLicense();

        if (\is_array($license)) {
            return \implode(', ', $license);
        }

        return $license;
    }

    /**
     * Get package homepage URL
     */
    public function getHomepage(): string
    {
        return $this->composerConfig['homepage'] ?? '';
    }

    /**
     * Get the package's source directories (usually "src")
     *
     * @return array<string>
     */
    public function getSourceDirectories(): array
    {
        // Check PSR-4 autoload configuration
        $psr4Dirs = [];
        if (isset($this->composerConfig['autoload']['psr-4'])) {
            foreach ($this->composerConfig['autoload']['psr-4'] as $dirs) {
                if (\is_array($dirs)) {
                    foreach ($dirs as $dir) {
                        $psr4Dirs[] = $dir;
                    }
                } else {
                    $psr4Dirs[] = $dirs;
                }
            }
        }

        // If we have PSR-4 directories, return them
        if (!empty($psr4Dirs)) {
            return \array_unique($psr4Dirs);
        }

        // Check PSR-0 autoload configuration as fallback
        $psr0Dirs = [];
        if (isset($this->composerConfig['autoload']['psr-0'])) {
            foreach ($this->composerConfig['autoload']['psr-0'] as $dirs) {
                if (\is_array($dirs)) {
                    foreach ($dirs as $dir) {
                        $psr0Dirs[] = $dir;
                    }
                } else {
                    $psr0Dirs[] = $dirs;
                }
            }
        }

        // If we have PSR-0 directories, return them
        if (!empty($psr0Dirs)) {
            return \array_unique($psr0Dirs);
        }

        // Check classmap autoload configuration as fallback
        $classmapDirs = [];
        if (isset($this->composerConfig['autoload']['classmap'])
            && \is_array($this->composerConfig['autoload']['classmap'])
        ) {
            foreach ($this->composerConfig['autoload']['classmap'] as $dir) {
                if (\is_string($dir)) {
                    $classmapDirs[] = $dir;
                }
            }
        }

        // If we have classmap directories, return them
        if (!empty($classmapDirs)) {
            return \array_unique($classmapDirs);
        }

        // Fallback to common source directories
        $commonDirs = ['src', 'lib', 'library'];
        foreach ($commonDirs as $dir) {
            if (\is_dir($this->path . '/' . $dir)) {
                return [$dir];
            }
        }

        // If no source directory is found, return the package root
        return ['.'];
    }

    /**
     * Get the package's keywords
     *
     * @return array<string>
     */
    public function getKeywords(): array
    {
        return $this->composerConfig['keywords'] ?? [];
    }

    /**
     * Get formatted keywords string
     */
    public function getFormattedKeywords(): string
    {
        $keywords = $this->getKeywords();
        if (empty($keywords)) {
            return '';
        }

        return \implode(', ', $keywords);
    }

    /**
     * Get the package type
     */
    public function getType(): string
    {
        return $this->composerConfig['type'] ?? 'library';
    }

    /**
     * Check if the package is abandoned
     */
    public function isAbandoned(): bool
    {
        return isset($this->composerConfig['abandoned']) &&
            ($this->composerConfig['abandoned'] === true || \is_string($this->composerConfig['abandoned']));
    }

    /**
     * Get the replacement package if abandoned
     */
    public function getReplacementPackage(): ?string
    {
        if ($this->isAbandoned() && \is_string($this->composerConfig['abandoned'])) {
            return $this->composerConfig['abandoned'];
        }

        return null;
    }

    /**
     * Get the package's support information
     *
     * @return array<string, string>
     */
    public function getSupport(): array
    {
        return $this->composerConfig['support'] ?? [];
    }

    /**
     * Get formatted support information
     */
    public function getFormattedSupport(): string
    {
        $support = $this->getSupport();
        if (empty($support)) {
            return '';
        }

        $result = [];

        if (isset($support['issues'])) {
            $result[] = "Issues: {$support['issues']}";
        }

        if (isset($support['source'])) {
            $result[] = "Source: {$support['source']}";
        }

        if (isset($support['docs'])) {
            $result[] = "Docs: {$support['docs']}";
        }

        if (isset($support['wiki'])) {
            $result[] = "Wiki: {$support['wiki']}";
        }

        if (isset($support['email'])) {
            $result[] = "Email: {$support['email']}";
        }

        if (isset($support['irc'])) {
            $result[] = "IRC: {$support['irc']}";
        }

        return \implode("\n", $result);
    }
}
