<?php

namespace FleekDash\API;

/**
 * Ensures Theme_Upgrader validates the correct folder inside extracted archives.
 *
 * WordPress uses file_exists() on a path derived from WP_Filesystem. On Windows, or when
 * archives contain extra root files alongside the theme folder, check_package() can inspect
 * the wrong directory and fail with "Template is missing" even though the theme is valid.
 */
final class ThemeDirectoryPackageResolver
{
    private const STYLE_CSS = 'style.css';

    /**
     * @param string|\WP_Error $source
     * @param mixed $_remoteSource Unused; required by upgrader_source_selection signature
     * @param mixed $upgrader
     * @param array<string, mixed> $hook_extra
     * @return string|\WP_Error
     */
    public static function resolveThemePackageSource($source, $_remoteSource, $upgrader, array $hook_extra) // NOSONAR php:S1172
    {
        $resolved = $source;

        if (!\is_wp_error($source) && $upgrader instanceof \Theme_Upgrader && ($hook_extra['type'] ?? '') === 'theme') {
            $themeRoot = self::findValidThemeRoot($source);
            if ($themeRoot !== null) {
                $resolved = self::ensureTrailingSlash($themeRoot);
            }
        }

        return $resolved;
    }

    /**
     * @param string $source Filesystem path from WP_Upgrader
     */
    private static function findValidThemeRoot(string $source): ?string
    {
        $localSource = self::toLocalPath($source);
        if ($localSource === '' || !\is_dir($localSource)) {
            return null;
        }

        if (self::isValidThemeRoot($localSource)) {
            return $source;
        }

        return self::findValidThemeRootInSubdirectories($source, $localSource);
    }

    private static function findValidThemeRootInSubdirectories(string $source, string $localSource): ?string
    {
        $entries = @\scandir($localSource);
        if ($entries === false) {
            return null;
        }

        foreach ($entries as $entry) {
            if ($entry === '.' || $entry === '..') {
                continue;
            }

            $resolved = self::resolveNestedThemeRoot($source, $localSource, $entry);
            if ($resolved !== null) {
                return $resolved;
            }
        }

        return null;
    }

    private static function resolveNestedThemeRoot(string $source, string $localSource, string $entry): ?string
    {
        $candidateLocal = self::ensureTrailingSlash($localSource) . $entry;
        if (!\is_dir($candidateLocal) || !self::isValidThemeRoot($candidateLocal)) {
            return null;
        }

        return self::ensureTrailingSlash($source) . $entry;
    }

    private static function isValidThemeRoot(string $directory): bool
    {
        $isValid = false;
        $stylePath = self::ensureTrailingSlash($directory) . self::STYLE_CSS;

        if (\file_exists($stylePath)) {
            $headers = \get_file_data(
                $stylePath,
                array(
                    'Name' => 'Theme Name',
                    'Template' => 'Template',
                ),
            );

            $hasThemeName = !empty($headers['Name']);
            $isChildTheme = !empty($headers['Template']);
            if ($hasThemeName) {
                $isValid = $isChildTheme || self::hasStandaloneThemeTemplate($directory);
            }
        }

        return $isValid;
    }

    private static function hasStandaloneThemeTemplate(string $directory): bool
    {
        $prefix = self::ensureTrailingSlash($directory);

        return \file_exists($prefix . 'index.php')
            || \file_exists($prefix . 'templates/index.html')
            || \file_exists($prefix . 'block-templates/index.html');
    }

    private static function toLocalPath(string $source): string
    {
        global $wp_filesystem;

        $normalizedSource = \wp_normalize_path($source);

        if (isset($wp_filesystem) && \is_object($wp_filesystem) && \method_exists($wp_filesystem, 'wp_content_dir')) {
            $fsContentDir = \wp_normalize_path((string) $wp_filesystem->wp_content_dir());
            $localContentDir = \wp_normalize_path(\trailingslashit(\WP_CONTENT_DIR));

            if ($fsContentDir !== '' && \str_starts_with($normalizedSource, $fsContentDir)) {
                $candidate = $localContentDir . \substr($normalizedSource, \strlen($fsContentDir));
                if (\is_dir($candidate)) {
                    return $candidate;
                }
            }
        }

        return \is_dir($normalizedSource) ? $normalizedSource : '';
    }

    private static function ensureTrailingSlash(string $path): string
    {
        return \str_ends_with($path, '/') ? $path : $path . '/';
    }
}
