<?php

namespace FleekDash\API;

/**
 * Normalizes WordPress.org theme API payloads for the theme directory REST layer.
 */
final class ThemeDirectoryFormatter
{
    /**
     * @param array<string, \WP_Theme> $installed_themes
     */
    public static function format(
        array|object $theme,
        array $installed_themes,
        \WP_Theme $current_theme,
        bool $full_details = false
    ): ?array {
        $themeObject = self::normalizeThemeObject($theme);
        if ($themeObject === null) {
            return null;
        }

        $formatted = self::buildBasePayload($themeObject);
        $formatted = self::applyAuthorFields($formatted, $themeObject);
        $formatted = self::applyInstalledState($formatted, $themeObject, $installed_themes, $current_theme);

        if ($full_details) {
            $formatted = self::appendFullDetails($formatted, $themeObject);
        }

        return $formatted;
    }

    private static function normalizeThemeObject(array|object $theme): ?object
    {
        if (\is_array($theme)) {
            $theme = (object) $theme;
        }

        if (!\is_object($theme) || !isset($theme->slug)) {
            return null;
        }

        return $theme;
    }

    private static function buildBasePayload(object $theme): array
    {
        return array(
            'slug' => self::getThemeProperty($theme, 'slug'),
            'name' => self::getThemeProperty($theme, 'name'),
            'description' => self::getThemeProperty($theme, 'description'),
            'version' => self::getThemeProperty($theme, 'version'),
            'author' => '',
            'author_url' => '',
            'homepage' => self::getThemeProperty($theme, 'homepage'),
            'rating' => isset($theme->rating) ? (float) $theme->rating : 0.0,
            'ratings' => isset($theme->ratings) ? (array) $theme->ratings : array(),
            'num_ratings' => isset($theme->num_ratings) ? (int) $theme->num_ratings : 0,
            'active_installs' => isset($theme->active_installs) ? (int) $theme->active_installs : 0,
            'downloaded' => isset($theme->downloaded) ? (int) $theme->downloaded : 0,
            'last_updated' => self::getThemeProperty($theme, 'last_updated'),
            'requires' => self::getThemeProperty($theme, 'requires'),
            'requires_php' => self::getThemeProperty($theme, 'requires_php'),
            'screenshot_url' => self::getThemeProperty($theme, 'screenshot_url'),
            'download_link' => self::getThemeProperty($theme, 'download_link'),
            'tags' => isset($theme->tags) ? (array) $theme->tags : array(),
            'is_installed' => false,
            'is_active' => false,
            'has_update' => false,
        );
    }

    /**
     * @param array<string, mixed> $formatted
     * @return array<string, mixed>
     */
    private static function applyAuthorFields(array $formatted, object $theme): array
    {
        if (!isset($theme->author)) {
            return $formatted;
        }

        $author = $theme->author;
        $displayName = '';
        $authorUrl = '';

        if (\is_array($author)) {
            $displayName = (string) ($author['display_name'] ?? '');
            $authorUrl = (string) ($author['author_url'] ?? '');
        } elseif (\is_object($author)) {
            $displayName = (string) ($author->display_name ?? '');
            $authorUrl = (string) ($author->author_url ?? '');
        } else {
            $displayName = (string) $author;
        }

        $formatted['author'] = $displayName;
        $formatted['author_url'] = $authorUrl;

        return $formatted;
    }

    /**
     * @param array<string, mixed> $formatted
     * @param array<string, \WP_Theme> $installed_themes
     * @return array<string, mixed>
     */
    private static function applyInstalledState(
        array $formatted,
        object $theme,
        array $installed_themes,
        \WP_Theme $current_theme
    ): array {
        $slug = (string) $theme->slug;
        if (!isset($installed_themes[$slug])) {
            return $formatted;
        }

        $installed = $installed_themes[$slug];
        $formatted['is_installed'] = true;
        $formatted['installed_version'] = $installed->get('Version');

        if ($current_theme->get_stylesheet() === $slug) {
            $formatted['is_active'] = true;
        }

        $remoteVersion = isset($theme->version) ? (string) $theme->version : '';
        if ($remoteVersion !== '' && \version_compare($remoteVersion, (string) $installed->get('Version'), '>')) {
            $formatted['has_update'] = true;
        }

        return $formatted;
    }

    /**
     * @param array<string, mixed> $formatted
     * @return array<string, mixed>
     */
    private static function appendFullDetails(array $formatted, object $theme): array
    {
        $formatted['sections'] = isset($theme->sections) ? (array) $theme->sections : array();
        $formatted['screenshots'] = isset($theme->screenshots) ? (array) $theme->screenshots : array();
        $formatted['versions'] = isset($theme->versions) ? (array) $theme->versions : array();

        return $formatted;
    }

    private static function getThemeProperty(object $theme, string $key, string $default = ''): string
    {
        if (!isset($theme->$key)) {
            return $default;
        }

        $value = $theme->$key;
        return \is_scalar($value) ? (string) $value : $default;
    }
}
