<?php
namespace App\Http\Services;

use App\Enums\StatusEnum;
use App\Models\AiSetting;
use App\Models\AiTemplate;
use App\Models\Core\Language;
use Illuminate\Http\Request;
use Illuminate\Support\Arr;
use App\Traits\ModelAction;
use Illuminate\Support\Str;
use Illuminate\Validation\Rule;
use Orhanerday\OpenAi\OpenAi;
use App\Traits\AccountManager;
use Illuminate\Support\Facades\Http;

class AiService
{

    use ModelAction, AccountManager;

    protected $user, $workspace;


    public function __construct()
    {
        $this->user = auth_user();
        $this->workspace = current_workspace();
    }

    /**
     * store template
     *
     * @param Request $request
     * @return void
     */
    public function saveTemplate(Request $request): array
    {

        $response = response_status('Template created successfully');
        try {
            $template = new AiTemplate();
            $template->name = $request->input("name");
            $template->platform_id = $request->input("platform_id");
            $template->user_id = $this->user->id;
            $template->prompt = $request->input("prompt");
            $template->save();

        } catch (\Exception $ex) {
            $response = response_status(strip_tags($ex->getMessage()), 'error');
        }

        return $response;

    }


    /**
     * update template
     *
     * @param Request $request
     * @return void
     */
    public function updateTemplate(Request $request): array
    {



        $response = response_status('Template updated successfully');

        try {
            $template = AiTemplate::findOrfail($request->input('id'));
            $template->name = $request->input("name");
            $template->platform_id = $request->input("platform_id");
            $template->user_id = $this->user->id;
            $template->prompt = $request->input("prompt");
            $template->save();
            $template->save();

        } catch (\Exception $ex) {
            $response = response_status($ex->getMessage(), 'error');
        }

        return $response;
    }


    public function setRules(Request $request): array
    {


        $rules = [
            "language" => ['required'],
            "custom_prompt" => ['required', Rule::in(StatusEnum::toArray())],

            "max_result" => [
                Rule::requiredIf(function () use ($request) {
                    return request()->routeIs('user.*');
                }),
                "nullable",
                "numeric",
                'gt:0',
                'max:5000'
            ],
            "ai_creativity" => ['nullable', Rule::in(array_values(Arr::get(config('settings'), 'default_creativity', [])))],
            "content_tone" => ['nullable', Rule::in(Arr::get(config('settings'), 'ai_default_tone', []))],
            "custom" => ['nullable', 'array']
        ];

        if (request()->input('custom_prompt') == StatusEnum::true->status()) {
            $rules['custom_prompt_input'] = ['required'];
        } else {
            $rules['id'] = ['required', "exists:ai_templates,id"];
        }


        $messages = [
            "language.required" => translate('Please select a input & output language'),
            "id.required" => translate('Please select a Template'),
            "max_result.required" => translate('Max result length field is required'),
            "custom_prompt.required" => translate('Prompt field is required'),
        ];

        if (
            request()->input('custom_prompt') == StatusEnum::false->status() &&
            request()->input('id')
        ) {
            $template = AiTemplate::find($request->input('id'));
            if ($template && $template->prompt_fields) {
                foreach ($template->prompt_fields as $key => $input) {
                    if ($input->validation == "required") {
                        $rules['custom.' . $key] = ['required'];
                    }
                }
            }
        }

        return [
            'template' => @$template,
            'rules' => $rules,
            'messages' => $messages,
        ];

    }


    public function setImageRules(Request $request): array
    {
        $rules = [
            "custom_prompt" => ['required', Rule::in(StatusEnum::toArray())],
            "max_result" => [
                Rule::requiredIf(fn() => request()->routeIs('user.*')),
                "nullable",
                "numeric",
                'gt:0',
                'max:10'
            ],
            "image_quality" => [
                'nullable',
                Rule::in(array_keys(Arr::get(config('settings'), 'ai_image_quality', ['standard', 'hd'])))
            ],
            "image_resolution" => [
                'nullable',
                Rule::in(array_keys(Arr::get(config('settings'), 'ai_image_resolution', ['256x256', '512x512', '1024x1024'])))
            ],
            "custom" => ['nullable', 'array']
        ];

        $messages = [
            "custom_prompt.required" => translate('Prompt field is required'),
            "max_result.required" => translate('Maximum number of images field is required'),
            "max_result.max" => translate('Maximum number of images cannot exceed 10'),
            "image_quality.in" => translate('Invalid image quality selected'),
            "image_resolution.in" => translate('Invalid image resolution selected'),
        ];

        if ($request->input('custom_prompt') == StatusEnum::true->status()) {
            $rules['custom_prompt_input'] = ['required'];
            $messages['custom_prompt_input.required'] = translate('Custom prompt input is required');
        } else {
            $rules['id'] = ['required', "exists:ai_templates,id"];
            $messages['id.required'] = translate('Please select a Template');
            $messages['id.exists'] = translate('Selected template does not exist');
        }

        $template = null;
        if ($request->input('custom_prompt') == StatusEnum::false->status() && $request->input('id')) {
            $template = AiTemplate::find($request->input('id'));
            if ($template && $template->prompt_fields) {
                foreach ($template->prompt_fields as $key => $input) {
                    if ($input->validation == "required") {
                        $rules['custom.' . $key] = ['required'];
                        $messages['custom.' . $key . '.required'] = translate('The ' . $key . ' field is required for the selected template');
                    }
                }
            }
        }

        return [
            'template' => $template,
            'rules' => $rules,
            'messages' => $messages,
        ];
    }

    public function setVideoRules(Request $request): array
    {
        $rules = [
            "custom_prompt" => ['required', Rule::in(StatusEnum::toArray())],
            "video_aspect_ratio" => [
                'nullable',
                Rule::in(array_keys(Arr::get(config('settings'), 'ai_video_aspect_ratio', ['9:16', '16:9', '1:1'])))
            ],
            "video_duration" => [
                'nullable',
                Rule::in(array_keys(Arr::get(config('settings'), 'ai_video_duration', ['5', '10'])))
            ],
            "custom" => ['nullable', 'array']
        ];

        $messages = [
            "custom_prompt.required" => translate('Prompt field is required'),
            "video_duration.in" => translate('Invalid video duratoin selected'),
            "video_resolution.in" => translate('Invalid video resolution selected'),
        ];

        if ($request->input('custom_prompt') == StatusEnum::true->status()) {
            $rules['custom_prompt_input'] = ['required'];
            $messages['custom_prompt_input.required'] = translate('Custom prompt input is required');
        } else {
            $rules['id'] = ['required', "exists:ai_templates,id"];
            $messages['id.required'] = translate('Please select a Template');
            $messages['id.exists'] = translate('Selected template does not exist');
        }

        $template = null;
        if ($request->input('custom_prompt') == StatusEnum::false->status() && $request->input('id')) {
            $template = AiTemplate::find($request->input('id'));
            if ($template && $template->prompt_fields) {
                foreach ($template->prompt_fields as $key => $input) {
                    if ($input->validation == "required") {
                        $rules['custom.' . $key] = ['required'];
                        $messages['custom.' . $key . '.required'] = translate('The ' . $key . ' field is required for the selected template');
                    }
                }
            }
        }

        return [
            'template' => $template,
            'rules' => $rules,
            'messages' => $messages,
        ];
    }

    public function generateTextContent(Request $request): array
    {
        try {
            $customPrompt = $request->input('prompt');
            $textModule = AiSetting::where('module', 'text_ai')->first();

            // Check if text AI module is configured
            if (!$textModule || !$textModule->config) {
                return [
                    'status' => false,
                    'message' => translate('Text AI module is not configured. Please configure AI settings first.'),
                    'text_content' => null
                ];
            }

            $moduleConfig = $textModule->config;

            // Check for API key - first try from module config, then fallback to site settings
            $apiKey = $moduleConfig['api_key'] ?? openai_key();
            if (empty($apiKey)) {
                return [
                    'status' => false,
                    'message' => translate('OpenAI API key is not configured. Please add your API key in AI Text Configuration settings.'),
                    'text_content' => null
                ];
            }

            $getBadWords = $moduleConfig['bad_words'] ?? [];

            if (is_array($getBadWords)) {
                $customPrompt = str_replace($getBadWords, "", $customPrompt);
            }

            $temperature = (float)($moduleConfig['default_creativity'] ?? 0.7);

            $aiParams = [
                'model' => $moduleConfig['model'] ?? 'gpt-3.5-turbo',
                'temperature' => $temperature,
                'presence_penalty' => 0.6,
                'frequency_penalty' => 0.2,
            ];

            $aiTone = $moduleConfig['default_tone'] ?? 'professional';
            $tokens = (int) ($moduleConfig['max_result'] ?? 150);
            $language = $request->input("language") ?? Language::default()->first()->lang_code ?? 'English';

            $customPrompt .= "\nPlease provide a concise and relevant response based on the following topic. Ensure the content is focused and informative, with no irrelevant information. The response should be in $language and use a $aiTone tone of voice. Focus on providing clarity and actionable insights. Do not include phrases like 'Of course' ,'certainly' or similar unnecessary introductory statements. If the topic is unclear, inform me without using excessive formalities or politeness.";

            // Build messages array with conversation history
            $messages = [];

            // Add conversation history if provided
            $conversationHistory = $request->input('conversation_history', []);
            if (!empty($conversationHistory) && is_array($conversationHistory)) {
                $messages = array_merge($messages, $conversationHistory);
            }

            // Add current user message
            $messages[] = [
                "role" => "user",
                "content" => $customPrompt
            ];

            $aiParams['messages'] = $messages;

            return $this->generateContent($aiParams, $apiKey);

        } catch (\Exception $e) {
            return [
                'status' => false,
                'message' => translate('AI text generation failed: ') . $e->getMessage(),
                'text_content' => null
            ];
        }
    }

    public function generateImageContent(Request $request): array
    {
        try {
            $customPrompt = $request->input('prompt');
            $imageModule = AiSetting::where('module', 'image_ai')->first();

            // Check if image AI module is configured
            if (!$imageModule || !$imageModule->config) {
                return [
                    'status' => false,
                    'message' => translate('Image AI module is not configured. Please configure AI settings first.'),
                    'image_content' => null
                ];
            }

            $moduleConfig = $imageModule->config;

            // Check for API key
            $apiKey = $moduleConfig['api_key'] ?? openai_Image_key();
            if (empty($apiKey)) {
                return [
                    'status' => false,
                    'message' => translate('Image AI API key is not configured. Please add your API key in settings.'),
                    'image_content' => null
                ];
            }

            $textModule = AiSetting::where('module', 'text_ai')->first();
            $getBadWords = ($textModule && $textModule->config) ? ($textModule->config['bad_words'] ?? []) : [];

            if (is_array($getBadWords)) {
                $customPrompt = str_replace($getBadWords, "", $customPrompt);
            }

            $imageQuality = $moduleConfig['image_quality'] ?? 'standard';
            $imageResolution = $moduleConfig['default_resolution'] ?? '512x512';
            $maxResult = isset($moduleConfig['max_result']) ? (int) $moduleConfig['max_result'] : 1;

            $aiParams = [
                'model' => $moduleConfig['model'] ?? 'dall-e-2',
                'prompt' => $customPrompt,
                'n' => min($maxResult, 1),
                'size' => $imageResolution,
            ];

            $customPrompt .= ' Generate a clear and relevant image based on the provided description. Ensure the content is safe, appropriate, and visually coherent. Avoid any copyrighted elements or inappropriate content.';

            $aiParams['prompt'] = $customPrompt;

            return $this->generateImage($aiParams, $apiKey);

        } catch (\Exception $e) {
            return [
                'status' => false,
                'message' => translate('AI image generation failed: ') . $e->getMessage(),
                'image_content' => null
            ];
        }
    }


    public function generateVideoContent(Request $request): array
    {
        try {
            $customPrompt = $request->input('prompt');
            $videoModule = AiSetting::where('module', 'video_ai')->first();

            // Check if video AI module is configured
            if (!$videoModule || !$videoModule->config) {
                return [
                    'status' => false,
                    'message' => translate('Video AI module is not configured. Please configure AI settings first.'),
                    'video_content' => null
                ];
            }

            $moduleConfig = $videoModule->config;

            // Check for API key
            $apiKey = $moduleConfig['api_key'] ?? kling_ai_video_key();
            if (empty($apiKey)) {
                return [
                    'status' => false,
                    'message' => translate('Video AI API key is not configured. Please add your API key in settings.'),
                    'video_content' => null
                ];
            }

            $textModule = AiSetting::where('module', 'text_ai')->first();
            $getBadWords = ($textModule && $textModule->config) ? ($textModule->config['bad_words'] ?? []) : [];

            if (is_array($getBadWords)) {
                $customPrompt = str_replace($getBadWords, "", $customPrompt);
            }

            $aiParams = $this->getModelSpecificParam($customPrompt, $moduleConfig);

            $customPrompt .= ' Generate a clear and relevant video based on the provided description. Ensure the content is safe, appropriate, and visually coherent. Avoid any copyrighted elements or inappropriate content.';

            $aiParams['prompt'] = $customPrompt;

            return $this->generateVideo($aiParams, $apiKey);

        } catch (\Exception $e) {
            return [
                'status' => false,
                'message' => translate('AI video generation failed: ') . $e->getMessage(),
                'video_content' => null
            ];
        }
    }




    public function getModelSpecificParam( $prompt , $moduleConfig)
    {


        $aiModel = $moduleConfig['model'];
        $params = [];


        switch ($aiModel) {
            case 'kling-v1':
                $params = [
                    'model_name' => "kling-v1",
                    'prompt' => $prompt,
                    'negative_prompt' => null,
                    'cfg_scale' => 0.5,
                    'mode' => 'std',
                    'aspect_ratio' => '16:9',
                    'duration' => 5,
                ];
                break;

            default:
                throw new Exception("Unsupported AI model: {$aiModel}");
        }

        return $params;
    }




    /**
     * Generate content using open ai
     *
     * @param array $aiParams
     * @param array $logData
     * @return array
     */
    public function generateContent(array $aiParams, string $apiKey = null): array
    {

        $status = false;
        $message = translate("Invalid Request");
        $actualApiKey = $apiKey ?? openai_key();
        $open_ai = new OpenAi(OPENAI_API_KEY: $actualApiKey);
        $chat_results = json_decode($open_ai->chat($aiParams), true);

        if (isset($chat_results['error'])) {
            $message = Arr::get($chat_results['error'], 'message', translate('Invalid Request'));
        } else {

            if (isset($chat_results['choices'][0]['message']['content'])) {

                $realContent = $chat_results['choices'][0]['message']['content'];
                $content = str_replace(["\r\n", "\r", "\n"], "<br>", $realContent);
                $content = preg_replace('/^"(.*)"$/', '$1', $content);
                $usage = $chat_results['usage'];

                $usage['model'] = $chat_results['model'];
                $usage['genarated_tokens'] = count(explode(' ', ($content)));



                $status = true;
                $message = $realContent;
            }


        }

        return [
            "status" => $status,
            "message" => $message,
            "content" => $status ? $message : null,
        ];

    }


    public function generateImage(array $aiParams, $key): array
    {
        $status = false;
        $message = translate("Invalid Request");

        $modelConfig = [
            'dall-e-2' => [
                'provider' => 'openai',
                'api_key_func' => 'openai_Image_key',
                'supported_sizes' => ['256x256', '512x512', '1024x1024'],
            ],
            'dall-e-3' => [
                'provider' => 'openai',
                'api_key_func' => 'openai_Image_key',
                'supported_sizes' => ['1024x1024', '1792x1024', '1024x1792'],
            ],

        ];

        if (!isset($aiParams['model']) || !isset($modelConfig[$aiParams['model']])) {
            return [
                'status' => $status,
                'message' => translate("Invalid or unsupported model. Supported models: " . implode(', ', array_keys($modelConfig))),
            ];
        }

        $config = $modelConfig[$aiParams['model']];
        $provider = $config['provider'];

        if (empty($aiParams['prompt'])) {
            return [
                'status' => $status,
                'message' => translate("Prompt is required"),
                'image_content' => null,
            ];
        }

        $size = $aiParams['size'] ?? '1024x1024';
        if (!in_array($size, $config['supported_sizes'])) {
            return [
                'status' => $status,
                'message' => translate("Invalid size for {$aiParams['model']}. Supported sizes: " . implode(', ', $config['supported_sizes'])),
                'image_content' => null,
            ];
        }


        $open_ai = new OpenAi(OPENAI_API_KEY: $key);
        $image_results = json_decode($open_ai->image($aiParams), true);



        try {

            if ($provider === 'openai') {
                $open_ai = new OpenAi(OPENAI_API_KEY: $key);
            } else {
                throw new \Exception("Unsupported provider: {$provider}");
            }

            $params = [
                'prompt' => $aiParams['prompt'],
                'model' => $aiParams['model'],
                'n' => $aiParams['n'] ?? 1,
                'size' => $size,
                'response_format' => $aiParams['response_format'] ?? 'url',
            ];


            $image_results = json_decode($open_ai->image($params), true);

            if (isset($image_results['error'])) {
                $message = Arr::get($image_results['error'], 'message', translate('Invalid Request'));
            } else {

                if (isset($image_results['data']) && is_array($image_results['data'])) {
                    $image_urls = array_map(fn($item) => $item['url'], $image_results['data']);

                    $status = true;
                    $message = translate('Image generated');
                }
            }
        } catch (\Exception $e) {
            $message = translate("Error generating image: ") . $e->getMessage();
        }

        return [
            'status' => $status,
            'message' => $message,
            'image_content' => $image_urls ?? null
        ];
    }


    public function generateVideo(array $aiParams, $key): array
    {
        $status = false;
        $message = translate("Invalid Request");
        $video_url = null;

        $modelConfig = [
            'kling-v1' => [
                'provider' => 'kling_ai',
                'api_key_func' => 'kling_ai_video_key',
                'supported_aspect_ratio' => ['9:16', '16:9', '1:1'],
                'task_endpoint' => 'https://api.klingai.com/v1/videos/text2video',
                'status_endpoint' => 'https://api.klingai.com/v1/videos/task',
            ],
        ];


        if (!isset($aiParams['model_name']) || !isset($modelConfig[$aiParams['model_name']])) {
            return [
                'status' => $status,
                'message' => translate("Invalid or unsupported model. Supported models: " . implode(', ', array_keys($modelConfig))),
                'video_content' => null,
            ];
        }

        $config = $modelConfig[$aiParams['model_name']];
        $provider = $config['provider'];

        if (empty($aiParams['prompt'])) {
            return [
                'status' => $status,
                'message' => translate("Prompt is required"),
                'video_content' => null,
            ];
        }


        $aspect_ratio = $aiParams['aspect_ratio'] ?? '16:9';
        if (!in_array($aspect_ratio, $config['supported_aspect_ratio'])) {
            return [
                'status' => $status,
                'message' => translate("Invalid aspect ratio for {$aiParams['model_name']}. Supported aspect ratios: " . implode(', ', $config['supported_aspect_ratio'])),
                'video_content' => null,
            ];
        }

        try {
            if ($provider === 'kling_ai') {
                $apiKey = $key;
                if (empty($apiKey)) {
                    throw new \Exception("API key is missing for Kling AI");
                }


                $payload = [
                    'prompt' => $aiParams['prompt'],
                    'aspect_ratio' => $aspect_ratio,
                    'duration' => $aiParams['duration'] ?? 5,
                    'fps' => 30,
                    'cfg_scale' => $aiParams['cfg_scale'] ?? 0.7,
                    'negative_prompt' => $aiParams['negative_prompt'] ?? 'blurry, distorted, unrealistic',
                    'external_task_id' => $aiParams['external_task_id'] ?? Str::uuid()->toString(),
                ];


                //video generation task
                $task_response = $this->makeKlingApiRequest($config['task_endpoint'], $payload, $apiKey, 'POST');
                $task_data = $task_response;

                if ($task_response->failed() || $task_data['code'] !== 0 || !isset($task_data['data']['task_id'])) {
                    throw new \Exception($task_data['message'] ?? translate("Failed to create video task"));
                }

                $task_id = $task_data['data']['task_id'];

                //Poll task status
                $max_attempts = 30;
                $attempt = 0;
                $poll_interval = 10;


                while ($attempt < $max_attempts) {
                    $status_response = $this->makeKlingApiRequest($config['status_endpoint'] . '/' . $task_id, [], $apiKey, 'GET');
                    $status_data = $status_response;

                    if ($status_response->failed() || $status_data['code'] !== 0) {
                        throw new \Exception($status_data['message'] ?? translate("Failed to retrieve task status"));
                    }

                    $task_status = $status_data['data']['task_status'];

                    if ($task_status === 'succeed') {
                        if (isset($status_data['data']['task_result']['videos'][0]['url'])) {
                            $video_url = $status_data['data']['task_result']['videos'][0]['url'];


                            // Log usage to database
                            $usage = [
                                'model' => $aiParams['model_name'],
                                'generated_videos' => 1,
                            ];



                            $status = true;
                            $message = translate('Video generated successfully');
                            break;
                        } else {
                            throw new \Exception("No video URL found in successful task");
                        }
                    } elseif ($task_status === 'failed') {
                        throw new \Exception($status_data['data']['task_status_msg'] ?? translate("Video generation task failed"));
                    }

                    $attempt++;
                    sleep($poll_interval);
                }

                if ($attempt >= $max_attempts) {
                    throw new \Exception(translate("Video generation timed out"));
                }
            } else {
                throw new \Exception("Unsupported provider: {$provider}");
            }
        } catch (\Exception $e) {
            $message = translate("Error generating video: ") . $e->getMessage();
        }

        return [
            'status' => $status,
            'message' => $message,
            'video_content' => [$video_url],
        ];
    }



    /**
     * Helper method to make API request to Kling AI using Laravel's HTTP client
     */
    private function makeKlingApiRequest(string $endpoint, array $payload, string $apiKey, string $method = 'POST')
    {

        $headers = [
            'Authorization' => 'Bearer ' . $apiKey,
            'Cache-Control' => 'no-cache',
        ];

        $request = Http::withHeaders($headers);

        if ($method === 'POST') {
            $response = $request->post($endpoint, $payload);
        } else {
            $response = $request->get($endpoint);
        }

        if ($response->failed()) {
            $error_message = $response->json('message', 'HTTP error ' . $response->status());
            throw new \Exception("API request failed with status {$response->status()}: $error_message");
        }

        return $response;
    }

    public function useMock($endpoint)
    {
        $useMock = true;

        if ($useMock) {
            if (str_contains($endpoint, 'https://api.klingai.com/v1/videos/text2video')) {
                return [
                    'code' => 0,
                    'message' => 'Task created successfully',
                    'data' => [
                        'task_id' => '12345-abcde-67890',
                    ],
                ];
            }


            if (str_contains($endpoint, 'https://api.klingai.com/v1/videos/task/12345-abcde-67890')) {
                return [
                    'code' => 0,
                    'message' => 'Task status retrieved successfully',
                    'data' => [
                        'task_status' => 'succeed',
                        'task_result' => [
                            'videos' => [
                                [
                                    'url' => 'https://www.w3schools.com/html/mov_bbb.mp4',
                                    'title' => 'Sample Video 1',
                                    'duration' => 120,
                                ],
                            ],
                        ],
                    ],
                ];
            }
        }
    }







}
