<?php
/**
 * Normalizes integrations from all sources into the Hub contract.
 *
 * @package FleekDash\Services
 */

namespace FleekDash\Services;

defined('ABSPATH') || exit;

class IntegrationNormalizerService
{
    private const DEFAULT_VERSION = '1.0.0';

    public const SOURCE_INTERNAL = 'internal';
    public const SOURCE_EXTERNAL = 'external';
    public const SOURCE_MU_PLUGIN = 'mu-plugin';
    public const SOURCE_PREMIUM_CATALOG = 'premium-catalog';

    /**
     * @param array<string, mixed> $integration
     * @return array<string, mixed>
     */
    public static function internal(string $id, array $integration): array
    {
        $config = is_array($integration['config'] ?? null) ? $integration['config'] : [];
        $source = ($integration['mode'] ?? '') === 'mu' ? self::SOURCE_MU_PLUGIN : self::SOURCE_INTERNAL;
        $settingsSchema = self::settingsSchema($config['settings_schema'] ?? ($config['settings'] ?? []));

        return self::withDefaults([
            'id' => $id,
            'integration_id' => $id,
            'name' => (string) ($integration['name'] ?? $config['name'] ?? $id),
            'description' => (string) ($integration['description'] ?? $config['description'] ?? ''),
            'version' => (string) ($integration['version'] ?? $config['version'] ?? self::DEFAULT_VERSION),
            'author' => (string) ($config['author'] ?? 'FleekDash'),
            'author_uri' => (string) ($config['author_uri'] ?? ''),
            'icon' => (string) ($config['icon'] ?? 'package'),
            'category' => self::category((string) ($integration['category'] ?? $config['category'] ?? 'plugin')),
            'mode' => (string) ($config['mode'] ?? ($integration['mode'] ?? 'available')),
            'source' => $source,
            'source_label' => self::sourceLabel($source),
            'integration_type' => $source === self::SOURCE_MU_PLUGIN ? 'mu-plugin' : 'internal',
            'plugin_file' => (string) ($config['plugin_file'] ?? "fleekdash-internal/{$id}.php"),
            'path' => (string) ($integration['path'] ?? ''),
            'is_active' => (bool) ($integration['is_active'] ?? false),
            'is_available' => (bool) ($integration['is_available'] ?? true),
            'is_installed' => (bool) ($integration['is_installed'] ?? true),
            'has_settings' => !empty($settingsSchema),
            'settings_schema' => $settingsSchema,
            'manifest' => self::internalManifest($id, $integration, $settingsSchema),
            'priority' => (int) ($config['priority'] ?? 100),
            'preview_link' => $config['preview_link'] ?? null,
            'roadmap_link' => $config['roadmap_link'] ?? null,
            'tags' => $config['tags'] ?? [],
            'feature_key' => $config['feature_key'] ?? null,
            'license_required' => (bool) ($config['license_required'] ?? false),
            'required_tier' => $config['required_tier'] ?? null,
            'allowed_roles' => self::roles($config['allowed_roles'] ?? null),
            'config' => $config,
        ]);
    }

    /**
     * @param array<string, mixed> $integration
     * @return array<string, mixed>
     */
    public static function registry(array $integration): array
    {
        $manifest = is_array($integration['manifest'] ?? null) ? $integration['manifest'] : [];
        $id = (string) ($integration['integration_id'] ?? $manifest['integration_id'] ?? $integration['id'] ?? '');
        $source = (string) ($integration['source'] ?? $manifest['source'] ?? self::SOURCE_EXTERNAL);
        $settingsSchema = self::settingsSchema($manifest['settings_schema'] ?? ($integration['settings_schema'] ?? []));

        return self::withDefaults([
            'id' => $id,
            'integration_id' => $id,
            'name' => (string) ($integration['name'] ?? $manifest['name'] ?? $id),
            'description' => (string) ($integration['description'] ?? $manifest['description'] ?? ''),
            'version' => (string) ($integration['version'] ?? $manifest['version'] ?? self::DEFAULT_VERSION),
            'author' => (string) ($integration['author'] ?? $manifest['author'] ?? ''),
            'author_uri' => (string) ($integration['author_uri'] ?? $manifest['author_uri'] ?? ''),
            'icon' => (string) ($integration['icon'] ?? $manifest['icon'] ?? 'package'),
            'category' => self::category((string) ($integration['category'] ?? $manifest['category'] ?? 'plugin')),
            'source' => $source,
            'source_label' => (string) ($integration['source_label'] ?? self::sourceLabel($source)),
            'integration_type' => (string) ($integration['integration_type'] ?? $manifest['integration_type'] ?? 'standalone'),
            'plugin_file' => (string) ($integration['plugin_file'] ?? $manifest['plugin_file'] ?? ''),
            'wp_menu_slug' => $integration['wp_menu_slug'] ?? $manifest['wp_menu_slug'] ?? null,
            'has_wp_menu' => (bool) ($integration['has_wp_menu'] ?? !empty($manifest['wp_menu_slug'])),
            'has_integration_routes' => (bool) ($integration['has_integration_routes'] ?? !empty($manifest['routes'])),
            'is_active' => (bool) ($integration['is_active'] ?? true),
            'is_available' => (bool) ($integration['is_available'] ?? true),
            'is_installed' => (bool) ($integration['is_installed'] ?? true),
            'has_settings' => !empty($settingsSchema),
            'settings_schema' => $settingsSchema,
            'manifest' => $manifest,
            'feature_key' => $integration['feature_key'] ?? $manifest['feature_key'] ?? null,
            'license_required' => (bool) ($integration['license_required'] ?? $manifest['license_required'] ?? false),
            'required_tier' => $integration['required_tier'] ?? $manifest['required_tier'] ?? null,
            'allowed_roles' => self::roles($integration['allowed_roles'] ?? $manifest['allowed_roles'] ?? null),
            'mode' => $manifest['mode'] ?? null,
            'tags' => $manifest['tags'] ?? [],
            'preview_link' => $manifest['preview_link'] ?? null,
            'roadmap_link' => $manifest['roadmap_link'] ?? null,
            'upgrade_message' => $manifest['upgrade_message'] ?? null,
            'upgrade_email' => $manifest['upgrade_email'] ?? null,
            'upgrade_subject' => $manifest['upgrade_subject'] ?? null,
        ]);
    }

    /**
     * @param array<string, mixed> $integration
     * @return array<string, mixed>
     */
    public static function catalog(array $integration): array
    {
        $id = (string) ($integration['integration_id'] ?? $integration['id'] ?? '');
        return self::withDefaults([
            'id' => $id,
            'integration_id' => $id,
            'name' => (string) ($integration['name'] ?? $id),
            'description' => (string) ($integration['description'] ?? ''),
            'version' => (string) ($integration['version'] ?? self::DEFAULT_VERSION),
            'icon' => (string) ($integration['icon'] ?? 'package'),
            'category' => (string) ($integration['category'] ?? 'app'),
            'source' => self::SOURCE_PREMIUM_CATALOG,
            'source_label' => self::sourceLabel(self::SOURCE_PREMIUM_CATALOG),
            'integration_type' => 'premium-catalog',
            'is_available' => false,
            'is_installed' => false,
            'license_required' => true,
            'feature_key' => $integration['feature_key'] ?? ('extension:' . $id),
            'required_tier' => $integration['required_tier'] ?? 'Agency',
            'upgrade_message' => $integration['upgrade_message'] ?? 'This premium extension is available as an add-on.',
            'mode' => (string) ($integration['mode'] ?? 'upcoming'),
            'preview_link' => $integration['preview_link'] ?? null,
            'roadmap_link' => $integration['roadmap_link'] ?? null,
            'tags' => $integration['tags'] ?? ['Premium'],
        ]);
    }

    /**
     * @param array<string, mixed> $base
     * @param array<string, mixed> $override
     * @return array<string, mixed>
     */
    public static function merge(array $base, array $override): array
    {
        $merged = array_merge($base, $override);
        $merged['config'] = $base['config'] ?? ($override['config'] ?? null);
        $merged['settings_schema'] = !empty($override['settings_schema'])
            ? $override['settings_schema']
            : ($base['settings_schema'] ?? null);
        $merged['has_settings'] = !empty($merged['settings_schema']);

        return $merged;
    }

    public static function sourceLabel(string $source): string
    {
        $label = null;

        switch ($source) {
            case self::SOURCE_INTERNAL:
                $label = 'Built-in';
                break;
            case self::SOURCE_MU_PLUGIN:
                $label = 'MU Plugin';
                break;
            case self::SOURCE_PREMIUM_CATALOG:
                $label = 'Premium';
                break;
            default:
                $label = 'Plugin';
                break;
        }

        return $label ?? 'Plugin';
    }

    /**
     * @param mixed $roles
     * @return array<int, string>|null
     */
    public static function roles($roles): ?array
    {
        if (is_string($roles)) {
            $decoded = json_decode($roles, true);
            $roles = is_array($decoded) ? $decoded : array_filter(array_map('trim', explode(',', $roles)));
        }

        if (!is_array($roles) || empty($roles)) {
            return null;
        }

        return array_values(array_filter(array_map('sanitize_key', $roles)));
    }

    /**
     * @param mixed $schema
     * @return array<string, array<string, mixed>>|null
     */
    public static function settingsSchema($schema): ?array
    {
        if (!is_array($schema) || empty($schema)) {
            return null;
        }

        $normalized = [];
        foreach ($schema as $key => $field) {
            if (!is_array($field)) {
                continue;
            }

            $fieldKey = sanitize_key((string) $key);
            $normalized[$fieldKey] = [
                'type' => (string) ($field['type'] ?? 'string'),
                'label' => (string) ($field['label'] ?? ucwords(str_replace('_', ' ', $fieldKey))),
                'description' => (string) ($field['description'] ?? ''),
                'required' => (bool) ($field['required'] ?? false),
                'encrypted' => (bool) ($field['encrypted'] ?? false),
                'default' => $field['default'] ?? null,
                'options' => $field['options'] ?? null,
                'min' => $field['min'] ?? null,
                'max' => $field['max'] ?? null,
                'step' => $field['step'] ?? null,
            ];
        }

        return $normalized ?: null;
    }

    private static function category(string $category): string
    {
        if ($category === 'ecommerce' || $category === '') {
            return 'plugin';
        }

        return $category;
    }

    /**
     * @param array<string, mixed> $integration
     * @param array<string, array<string, mixed>>|null $settingsSchema
     * @return array<string, mixed>
     */
    private static function internalManifest(string $id, array $integration, ?array $settingsSchema): array
    {
        $config = is_array($integration['config'] ?? null) ? $integration['config'] : [];

        return [
            'integration_id' => $id,
            'name' => $config['name'] ?? $integration['name'] ?? $id,
            'description' => $config['description'] ?? $integration['description'] ?? '',
            'version' => $config['version'] ?? $integration['version'] ?? self::DEFAULT_VERSION,
            'author' => $config['author'] ?? 'FleekDash',
            'author_uri' => $config['author_uri'] ?? '',
            'integration_type' => ($integration['mode'] ?? '') === 'mu' ? 'mu-plugin' : 'internal',
            'plugin_file' => $config['plugin_file'] ?? "fleekdash-internal/{$id}.php",
            'icon' => $config['icon'] ?? 'package',
            'category' => $config['category'] ?? $integration['category'] ?? 'plugin',
            'source' => ($integration['mode'] ?? '') === 'mu' ? self::SOURCE_MU_PLUGIN : self::SOURCE_INTERNAL,
            'settings_schema' => $settingsSchema,
            'feature_key' => $config['feature_key'] ?? null,
            'license_required' => (bool) ($config['license_required'] ?? false),
            'required_tier' => $config['required_tier'] ?? null,
            'allowed_roles' => self::roles($config['allowed_roles'] ?? null),
        ];
    }

    /**
     * @param array<string, mixed> $data
     * @return array<string, mixed>
     */
    private static function withDefaults(array $data): array
    {
        return array_merge([
            'id' => '',
            'integration_id' => '',
            'name' => '',
            'description' => '',
            'version' => self::DEFAULT_VERSION,
            'icon' => 'package',
            'category' => 'plugin',
            'source' => self::SOURCE_EXTERNAL,
            'source_label' => self::sourceLabel(self::SOURCE_EXTERNAL),
            'integration_type' => 'standalone',
            'is_active' => false,
            'is_available' => true,
            'is_installed' => true,
            'has_settings' => false,
            'settings_schema' => null,
            'license_required' => false,
            'has_feature_access' => true,
            'required_tier' => null,
            'user_tier' => null,
            'allowed_roles' => null,
            'feature_key' => null,
            'tags' => [],
        ], $data);
    }
}
