<?php

namespace OtomaticAi\Controllers;

use Exception;
use OtomaticAi\Api\Haloscan\Client;
use OtomaticAi\Models\Presets\Preset;
use OtomaticAi\Utils\Language;
use OtomaticAi\Vendors\Illuminate\Support\Arr;
use OtomaticAi\Vendors\Illuminate\Support\Str;

class KeywordController extends Controller
{
    public function generate()
    {
        $this->verifyNonce();

        $this->validate([
            "source" => ["required", "string"],
            "language" => ["required", "string"],
            "keyword" => ["required_unless:source,haloscan_domain", "string"],
            "url" => ["required_if:source,haloscan_domain", "string"],
            "length" => ["nullable", "integer"],
        ]);

        switch ($this->input('source')) {
            case "openai_related":
                $response["keywords"] = $this->makeOpenAIResponse("generate_related_keywords");
                break;
            case "openai_similar":
                $response["keywords"] = $this->makeOpenAIResponse("generate_similar_keywords");
                break;
            case "openai_questions":
                $response["keywords"] = $this->makeOpenAIResponse("generate_question_keywords");
                break;
            case "openai_brands":
                $response["keywords"] = $this->makeOpenAIResponse("generate_brand_keywords");
                break;
            case "openai_species":
                $response["keywords"] = $this->makeOpenAIResponse("generate_species_keywords");
                break;
            case "openai_jobs":
                $response["keywords"] = $this->makeOpenAIResponse("generate_jobs_keywords");
                break;
            case "openai_personalities":
                $response["keywords"] = $this->makeOpenAIResponse("generate_personalities_keywords");
                break;
            case "openai_cities":
                $response["keywords"] = $this->makeOpenAIResponse("generate_cities_keywords");
                break;
            case "haloscan_match":
                $response["keywords"] = $this->makeHaloScanMatchResponse();
                break;
            case "haloscan_similar":
                $response["keywords"] = $this->makeHaloScanSimilarResponse();
                break;
            case "haloscan_related":
                $response["keywords"] = $this->makeHaloScanRelatedResponse();
                break;
            case "haloscan_questions":
                $response["keywords"] = $this->makeHaloScanQuestionsResponse();
                break;
            case "haloscan_domain":
                $response["keywords"] = $this->makeHaloScanDomainResponse();
                break;
        }

        $this->response($response);
    }

    public function analyse()
    {
        $this->verifyNonce();

        $this->validate([
            "language" => ["required", "string"],
            "keywords" => ["required", "array"],
        ]);

        // call haloscan api
        try {
            $api = new Client();

            $keywords = [];
            foreach ($this->input('keywords', []) as $keyword) {
                $keyword = trim($keyword);
                $key = Str::lower($keyword);
                $keywords[$key] = $keyword;
            }

            $results = Arr::get($api->keywordsBulk([
                "keywords" => array_keys($keywords),
                "lineCount" => count(array_keys($keywords))
            ]), "results", []);

            $results = Arr::map($results, function ($result) use ($keywords) {
                return [
                    "keyword" => Arr::get($keywords, $result["keyword"], $result["keyword"]),
                    "volume" => Arr::get($result, "volume", 0),
                    "difficulty" => Arr::get($result, "kgr", 0),
                    "cpc" => Arr::get($result, "cpc", 0),
                ];
            });

            $this->response($results);
        } catch (Exception $e) {
            $this->response(["message" => "An error occurred", "error" => $e->getMessage()], 503);
        }
    }

    private function makeOpenAIResponse(string $preset): array
    {
        try {
            // get the openai preset
            $preset = Preset::findFromAPI($preset);

            // make payload
            $payload = [
                "request" => $this->input('keyword'),
                "language" => Language::find($this->input('language', 'en'))->value,
                "length" => $this->input('length', 50),
            ];

            // run the preset
            $response = $preset->process($payload);

            // get the response content
            $response = json_decode(Arr::get($response, 'choices.0.message.content'), true, 512, JSON_THROW_ON_ERROR);
            $items = Arr::get($response, "values");

            if (!empty($items)) {
                $items = array_map(function ($str) {
                    return Str::clean($str);
                }, $items);
                $items = array_values(array_filter($items, function ($str) {
                    return !empty($str);
                }));
            }

            return $items;
        } catch (Exception $e) {
            $this->response(["message" => "An error occurred", "error" => $e->getMessage()], 503);
        }
    }

    private function makeHaloScanMatchResponse(): array
    {
        // call haloscan api
        try {
            $api = new Client();
            $results = Arr::get($api->keywordsMatch([
                "keyword" => $this->input('keyword'),
                "lineCount" => $this->input('length', 50),
            ]), "results", []);

            $items = Arr::pluck($results, 'keyword');

            return $items;
        } catch (Exception $e) {
            $this->response(["message" => "An error occurred", "error" => $e->getMessage()], 503);
        }
    }

    private function makeHaloScanSimilarResponse(): array
    {
        // call haloscan api
        try {
            $api = new Client();
            $results = Arr::get($api->keywordsSimilar([
                "keyword" => $this->input('keyword'),
                "lineCount" => $this->input('length', 50),
            ]), "results", []);

            $items = Arr::pluck($results, 'keyword');

            return $items;
        } catch (Exception $e) {
            $this->response(["message" => "An error occurred", "error" => $e->getMessage()], 503);
        }
    }

    private function makeHaloScanRelatedResponse(): array
    {
        // call haloscan api
        try {
            $api = new Client();
            $results = Arr::get($api->keywordsRelated([
                "keyword" => $this->input('keyword'),
                "lineCount" => $this->input('length', 50),
            ]), "results", []);

            $items = Arr::pluck($results, 'keyword');

            return $items;
        } catch (Exception $e) {
            $this->response(["message" => "An error occurred", "error" => $e->getMessage()], 503);
        }
    }

    private function makeHaloScanQuestionsResponse(): array
    {
        // call haloscan api
        try {
            $api = new Client();
            $results = Arr::get($api->keywordsQuestions([
                "keyword" => $this->input('keyword'),
                "lineCount" => $this->input('length', 50),
            ]), "results", []);

            $items = Arr::pluck($results, 'keyword');

            return $items;
        } catch (Exception $e) {
            $this->response(["message" => "An error occurred", "error" => $e->getMessage()], 503);
        }
    }

    private function makeHaloScanDomainResponse(): array
    {
        // call haloscan api
        try {
            $api = new Client();
            $results = Arr::get($api->domainsPositions([
                "input" => $this->input('url'),
                "lineCount" => $this->input('length', 50),
            ]), "results", []);

            $items = Arr::pluck($results, 'keyword');

            return $items;
        } catch (Exception $e) {
            $this->response(["message" => "An error occurred", "error" => $e->getMessage()], 503);
        }
    }
}
