<?php

namespace SEOAIC\posts_mass_actions;

use Exception;
use SEOAIC\content_editor_blocks\providers\SEOAICBlocks;
use SEOAIC\helpers\HTMLBuilers;
use SEOAIC\helpers\SEOPluginsHelper;
use SEOAIC\patterns\LeadsFormPattern;
use SEOAIC\SEOAIC_SETTINGS;
use SEOAIC\thirdparty_plugins_meta_tags\YoastMetaTags;
use SEOAIC\traits\Debug;
use WP_Post;
use WP_REST_Request;

class FAQGenerate extends AbstractPostsMassAction
{
    use Debug;

    private const PER_REQUEST__UPDATES_CONTENT = 5;
    private const PENDING_STATUS = 'pending';
    private const FAILED_STATUS = 'failed';
    private const COMPLETED_STATUS = 'completed';
    public const PRIMARY_GOAL_OPTIONS = [
        'lead_qualification'    => 'Lead Qualification',
        'service_inquiry'       => 'Service Inquiry',
        'custom_interaction'    => 'Custom Interaction',
    ];

    public function __construct($seoaic)
    {
        parent::__construct($seoaic);

        $this->backendActionURL = 'api/ai/posts/faq';
        $this->backendCheckStatusURL = 'api/ai/posts/faq/status';
        $this->backendContentURL = 'api/ai/posts/faq/content';
        $this->backendClearURL = 'api/ai/posts/faq/clear';
        $this->statusField = 'seoaic_faq_generate_status';
        // $this->cronCheckStatusHookName = 'seoaic/leads_form/generate/check_status_cron_hook';

        $this->successfullRunMessage = 'Generation started';
        $this->completeMessage = 'All posts have been updated with FAQ section.';
        $this->stopMessage = 'FAQ generation have been stopped.';
    }

    public static function init()
    {
        // see SEOAIC_POSTS __construct function
        global $SEOAIC;

        $self = new self($SEOAIC);
        add_action($self->cronCheckStatusHookName, [$self, 'cronPostsCheckStatus']);
    }

    public function prepareData($request)
    {
        $postIDs = [];

        if (is_array($request['post-mass-edit'])) {
            $postIDs = $request['post-mass-edit'];
        } else {
            $postIDs = [$request['post-mass-edit']];
        }

        // make sure posts are available
        $posts = $this->getAvailablePostsForLeadsGeneration($postIDs);

        if (empty($posts)) {
            throw new Exception('Posts not found');
        }

        $postsData = array_map(function (WP_Post $post) {
            return [
                'post_id'       => $post->ID,
                'post_content'  => $post->post_content,
                'language'      => $this->seoaic->multilang->get_post_language($post->ID),
            ];
        }, $posts);

        $data   = [
            'faq_prompt'    => sanitize_textarea_field($request['custom_prompt']),
            'posts'         => $postsData,
        ];

        return $data;
    }

    public function prepareDataFromAPIRequest(WP_REST_Request $request)
    {
        $postID = intval($request->get_param('post_id'));
        $post   = get_post($postID);
        $data   = [
            'faq_prompt'    => sanitize_textarea_field($request->get_param('prompt')),
            'posts'         => [
                [
                    'post_id'       => $postID,
                    'post_content'  => $post->post_content,
                    'language'      => $this->seoaic->multilang->get_post_language($postID),
                ]
            ],
        ];

        return $data;
    }

    /**
     * Override parent's method to be able to make requests in a loop
     */
    public function sendActionRequest($data = [])
    {
        $this->debugLog(__CLASS__, 'Data: ',  $data);
        $result = $this->sendRequest($this->getBackendActionURL(), $data);
        $this->debugLog(__CLASS__, 'Response: ',  $result);
        $result['posts_data'] = $data['posts'];

        return $result;
    }

    public function processActionResults($result = [])
    {
        if (
            !empty($result['status'])
            && 'success' == $result['status']
            && !empty($result['posts_data'])
        ) {
            foreach ($result['posts_data'] as $postData) {
                $this->updatePostData($postData['post_id'], [
                    $this->getStatusField() => self::PENDING_STATUS,
                ]);
            }

        } else {
            if (!empty($result['message'])) {
                $this->errors[] = $result['message'];
            }

            foreach ($result['posts_data'] as $postData) {
                $this->updatePostData($postData['id'], [
                    $this->getStatusField() => '',
                ]);
            }
        }

        if ($this->useCron) {
            $this->registerPostsCheckStatusCron();
        }

        return true;
    }

    public function pocessCheckStatusResults($result)
    {
        $returnData = [
            'done' => [],
            'failed' => [],
        ];

        if (!empty($result)) {
            if (
                !empty($result['completed'])
                && is_array($result['completed'])
            ) {
                $returnData['done'] = $this->processCompleted($result['completed']);
            }

            if (!empty($result['failed'])) {
                $this->processFailed($result['failed']);
                $returnData['failed'] = array_merge($returnData['failed'], $result['failed']);
            }
        }

        return $returnData;
    }

    protected function processCompleted($ids = [])
    {
        if (
            empty($ids)
            || !is_array($ids)
        ) {
            return;
        }

        // doublecheck the IDs to exist
        $posts = $this->getGeneratingPostsByIDs($ids, false, true);
        if (empty($posts)) {
            return;
        }

        $postsByIDs = array_combine(array_column($posts, 'ID'), $posts);

        // change status
        foreach ($postsByIDs as $origPost) {
            $this->updatePostData($origPost->ID, [
                $this->getStatusField() => 'completed',
            ]);
        }

        $postIDs = array_map(function ($item) {
            return $item->ID;
        }, $posts);

        $data = [
            'post_ids' => $postIDs,
        ];
        $return = [];
        $contentResult = $this->sendContentRequest($data);

        if (
            !empty($contentResult)
            && is_array($contentResult)
        ) {
            foreach ($contentResult as $item) {
                if (
                    empty($item)
                    || empty($item['postId'])
                    || empty($item['content'])
                    || !in_array($item['postId'], $postIDs)
                ) {
                    continue;
                }

                if (!empty($item['content'])) {
                    $faqContent = (new SEOAICBlocks())->faq($item['content']);

                    // save in content only for for ajax requests, not for API ones
                    if (!$this->isAPI) {
                        $postContent = $postsByIDs[$item['postId']]->post_content;
                        wp_update_post([
                            "ID"            => $item['postId'],
                            "post_content"  => $postContent . '<br>' . $faqContent,
                        ]);
                    }
                }

                $return[$item['postId']] = [
                    'id'        => $item['postId'],
                    'content'   => $item['content'],
                ];
            }
        }

        return $return;
    }

    protected function processFailed($ids = [])
    {
        if (
            !empty($ids)
            && is_array($ids)
        ) {
            // doublecheck the IDs to exist
            $posts = $this->getGeneratingPostsByIDs($ids, false, true);
            if (empty($posts)) {
                return;
            }

            $postsByIDs = array_combine(array_column($posts, 'ID'), $posts);

            // change status
            foreach ($postsByIDs as $origPost) {
                $this->updatePostData($origPost->ID, [
                    $this->getStatusField() => self::FAILED_STATUS,
                ]);
            }
        }
    }

    public function isRunning()
    {
        $posts = $this->getGeneratingFAQPostsAll();

        return !empty($posts);
    }

    public function cronPostsCheckStatus()
    {
        $this->debugLog('[CRON]', __CLASS__);
        $this->getStatusResults();
    }

    public function stop()
    {
        $this->seoaic->posts->debugLog();
        $posts = $this->getGeneratingFAQPostsAll();

        if (!empty($posts)) {
            foreach ($posts as $post) {
                $this->updatePostData($post->ID, [
                    $this->getStatusField() => '',
                ]);
            }
        }

        $this->sendClearRequest(['full' => true]);
        $this->unregisterPostsCheckStatusCron();
    }


    /**
     * Gets available posts for Leads geneartion, e.g. not in "Pending" state
     * @param array $postIDs options array of IDs to search among
     * @return array
     */
    private function getAvailablePostsForLeadsGeneration($postIDs = [])
    {
        $args = [
            'posts_per_page'    => -1,
            'post_type'         => 'any',
            'post_status'       => 'any',
            'lang'              => '', // disable default lang setting
            'skip_hiding'       => true,
            'meta_query'        => [
                'relation' => 'OR',
                [
                    'key' => $this->getStatusField(),
                    'value' => self::PENDING_STATUS,
                    'compare' => '!=',
                ],
                [
                    'key' => $this->getStatusField(),
                    'compare' => 'NOT EXISTS',
                ],
            ],
        ];

        if (!empty($postIDs)) {
            $postIDs = !is_array($postIDs) ? [$postIDs] : $postIDs;
            $args['post__in'] = $postIDs;
        }
        $posts = get_posts($args);

        return $posts;
    }

    /**
     * Gets all posts what we generate FAQ section for
     * @param array $postIDs options array of IDs to search among
     * @return array
     */
    public function getGeneratingFAQPostsAll()
    {
        $args = [
            'posts_per_page'    => -1,
            'post_type'         => 'any',
            'post_status'       => 'any',
            'lang'              => '', // disable default lang setting
            'skip_hiding'       => true,
            'meta_query'        => [
                'relation' => 'AND',
                [
                    'key' => $this->getStatusField(),
                    'value' => self::PENDING_STATUS,
                    'compare' => '=',
                ],
            ],
        ];

        $posts = get_posts($args);

        return $posts;
    }

    /**
     * @param array|int $ids Accepts array if IDs or single ID
     */
    private function getGeneratingPostsByIDs($ids = [], $returnIDsOnly = false, $all = false)
    {
        $args = [
            'numberposts'       => ($all ? -1 : self::PER_REQUEST__UPDATES_CONTENT),
            'post_type'         => 'any',
            'post_status'       => 'any',
            'lang'              => '', // disable default lang setting
            'skip_hiding'       => true,
            'meta_query'        => [
                'relation' => 'AND',
                [
                    'key' => $this->getStatusField(),
                    'value' => self::PENDING_STATUS,
                    'compare' => '=',
                ],
            ],
        ];

        if (!empty($ids)) {
            $args['include'] = !is_array($ids) ? [$ids] : $ids;
        }

        if ($returnIDsOnly) {
            $args['fields'] = 'ids';
        }

        $posts = get_posts($args);

        return $posts;
    }

    public function resetPostStatus(int $postID)
    {
        $this->updatePostData($postID, [
            $this->getStatusField() => '',
        ]);
    }
}
