<?php

namespace lucidpen;

if (!defined('ABSPATH'))
    exit;

use core\Result;
use core\SingletonTrait;
use RuntimeException;

/**
 * AIServiceManager
 * Manages the registration and retrieval of AI services.
 */
class AIServiceManager
{
    use SingletonTrait;

    /**
     * @var array<string, array{name: string, description: string, callback: callable}>
     */
    private $service_registry = [];

    private function __construct()
    {
        // add_action('init', [$this, 'init_services']);
        add_action('lucidpen_addons_loaded', [$this, 'init_services'],20);

    }

    /**
     * Trigger registration for all AI services
     */
    public function init_services(): void
    {
        do_action('lucidpen-register-ai-service', $this);
    }

    /**
     * Register an AI service.
     *
     * @param string $name Unique ID (e.g. 'azure')
     * @param string $description Human-friendly label
     * @param callable $callback Must return AIServiceAbstract
     */
    public function register_service(string $name, string $description, callable $callback): void
    {
        if (isset($this->service_registry[$name])) {
            Logger::info("[AIServiceManager] Duplicate registration for service '$name'. Skipped.");
            return;
        }

        $this->service_registry[$name] = [
            'name' => $name,
            'description' => $description,
            'callback' => $callback,
        ];
    }

    /**
     * @return array<string, string> Map of service key => description
     */
    public function get_registered_services(): array
    {
        $output = [];
        foreach ($this->service_registry as $id => $meta) {
            $output[$id] = $meta['description'];
        }
        return $output;
    }

    public function get_selected_service_id(): string
    {
        $service_id = null;
        # check if 'enigtech' exists in the registry
        if (isset($this->service_registry['enigtech'])) {
            $service_id = 'enigtech';
        }
        // Fallback to the default service if 'enigtech' is not registered
        else {
            $service_id = get_option('lucidpen_selected_ai_service', 'azure');
        }

        Logger::info("[AIServiceManager] Using '$service_id' as the selected AI service.");
        return $service_id;



    }


    public function get_service(): AIServiceAbstract
    {
        $id = $this->get_selected_service_id();

        if (!isset($this->service_registry[$id])) {
            $message = "[AIServiceManager] Service '$id' not found in registry.";
            throw new RuntimeException(esc_html($message));
        }

        $callback = $this->service_registry[$id]['callback'];
        $service = call_user_func($callback);

        if (!$service instanceof AIServiceAbstract) {
            $message = "[AIServiceManager] Service '$id' did not return a valid AIServiceAbstract.";
            throw new RuntimeException(esc_html($message));
        }

        return $service;
    }
}


/**
 * Abstract class for AI services.
 * All AI service implementations must extend this class.
 */
abstract class AIServiceAbstract
{
    private array $default_options = [];

    /**
     * Call this in each subclass file (not in __construct).
     * Hooks the static `register_service` method into the WordPress action.
     */
    public static function setup_registration(): void
    {
        add_action('lucidpen-register-ai-service', [static::class, 'register_service']);
    }

    /**
     * Static registration logic, common to all services.
     */
    public static function register_service(AIServiceManager $manager): void
    {
        $desc = static::get_profile();

        if (empty($desc['name']) || empty($desc['description'])) {
            Logger::error("[AIServiceAbstract] get_profile() must return name and description.");
            return;
        }

        $manager->register_service(
            $desc['name'],
            $desc['description'],
            fn() => static::get_instance()
        );
    }

    /**
     * Subclasses return ['name' => 'azure', 'description' => 'Azure OpenAI']
     */
    abstract protected static function get_profile(): array;

    protected static function get_instance(): AIServiceAbstract
    {
        return new static();
    }

    public function get_default_options(): array
    {
        return $this->default_options;
    }

    public function set_default_options(array $options): void
    {
        $this->default_options = $options;
    }

    abstract public function chat(array $messages, array $options = null): Result;
}
