<?php

namespace OtomaticAi\Utils;

use OtomaticAi\Vendors\Illuminate\Support\Collection;
use OtomaticAi\Api\OpenAi\PoolClient as PoolOpenAiClient;
use OtomaticAi\Api\Anthropic\PoolClient as PoolAnthropicClient;
use OtomaticAi\Api\Groq\PoolClient as PoolGroqClient;
use OtomaticAi\Api\MistralAi\PoolClient as PoolMistralAiClient;
use OtomaticAi\Api\DeepSeek\PoolClient as PoolDeepSeekClient;
use OtomaticAi\Models\Presets\AnthropicPreset;
use OtomaticAi\Models\Presets\GroqPreset;
use OtomaticAi\Models\Presets\MistralAIPreset;
use OtomaticAi\Models\Presets\OpenAIPreset;
use OtomaticAi\Models\Presets\DeepSeekPreset;
use OtomaticAi\Models\Presets\Preset;
use OtomaticAi\Vendors\Illuminate\Support\Arr;

class PresetCollection extends Collection
{
    public function process(array $params = [])
    {
        $grouped = [];

        $this->each(function (Preset $preset, int $index) use (&$grouped) {
            $class = get_class($preset);
            if (!isset($grouped[$class])) {
                $grouped[$class] = [];
            }

            $grouped[$class][] = [
                "preset" => $preset,
                "index" => $index,
            ];
        });

        $results = [];

        foreach ($grouped as $class => $presets) {
            $api = null;
            switch ($class) {
                case OpenAIPreset::class:
                    $api = new PoolOpenAiClient;
                    break;
                case AnthropicPreset::class:
                    $api = new PoolAnthropicClient;
                    break;
                case GroqPreset::class:
                    $api = new PoolGroqClient;
                    break;
                case MistralAIPreset::class:
                    $api = new PoolMistralAiClient;
                    break;
                case DeepSeekPreset::class:
                    $api = new PoolDeepSeekClient;
                    break;
            }

            if ($api) {
                $payloads = [];
                foreach ($presets as $index => $preset) {
                    $payloads[] = $preset["preset"]->payload(Arr::get($params, $preset["index"], []));
                }

                $groupedResults = [];

                switch ($class) {
                    case OpenAIPreset::class:
                        $groupedResults = $api->chat($payloads);
                        break;
                    case AnthropicPreset::class:
                        $groupedResults = $api->messages($payloads);
                        $groupedResults = array_map(function ($response) {
                            Arr::set($response, "choices.0.message.content", Arr::get($response, "content.0.text"));
                            return $response;
                        }, $groupedResults);
                        break;
                    case GroqPreset::class:
                        $groupedResults = $api->chat($payloads);
                        break;
                    case MistralAIPreset::class:
                        $groupedResults = $api->chat($payloads);
                        break;
                    case DeepSeekPreset::class:
                        $groupedResults = $api->chat($payloads);
                        break;
                }

                ksort($groupedResults);

                foreach ($presets as $index => $preset) {
                    Arr::set($results, $preset["index"], Arr::get($groupedResults, $index));
                }
            }
        }

        ksort($results);

        return $results;
    }

    static function run(array $params = [])
    {
        $presets = Arr::pluck($params, 0);

        $payloads = [];
        foreach ($presets as $index => $preset) {
            $payloads[] = Arr::get($params, $index . '.1', []);
        }

        $collection = new self($presets);
        $results = $collection->process($payloads);

        foreach ($presets as $index => $preset) {
            if (isset($results[$index]) && $params[$index][2] && is_callable($params[$index][2])) {
                $params[$index][2]($results[$index], $preset, $payloads[$index]);
            }
        }

        return $results;
    }
}
