<?php

namespace SEOAIC;

use SEOAIC\relations\KeywordsPostsRelation;
use WP_Query;

class SeoaicInternalLinks
{
    private $seoaic;
    private $internalLinks;

    public function __construct($seoaic)
    {
        $this->seoaic = $seoaic;
        $this->internalLinks = [];
    }

    public function get()
    {
        return $this->internalLinks;
    }

    /**
     * Converts from array of internal links to string which is used for posts generation
     * @return string Formatted string
     */
    public function toString(): string
    {
        $internalLinksString = $this->makeInternalLinksPermalinkAndTitleString($this->internalLinks);

        return $internalLinksString;
    }

    public function toOptionsDataArray(): array
    {
        $result = [];

        foreach ($this->internalLinks as $internalLink) {
            if (is_string($internalLink)) {
                $result[] = [
                    'id'        => $internalLink,
                    'title'     => $internalLink,
                    'status'    => '',
                    'status_readable' => '',
                    'link'      =>  $internalLink,
                ];
            } else if (!empty($internalLink->ID)) {
                switch ($internalLink->post_status) {
                    case 'publish':
                        $statusReadable = esc_html__("Published", "seoaic");
                        break;

                    case 'draft':
                        $statusReadable = esc_html__("Draft", "seoaic");
                        break;

                    default:
                        $statusReadable = $internalLink->post_status;
                }

                $result[] = [
                    'id'        => (int)$internalLink->ID,
                    'title'     => $internalLink->post_title,
                    'status'    => $internalLink->post_status,
                    'status_readable' => $statusReadable,
                    'link'      =>  get_permalink($internalLink),
                ];
            }
        }

        return $result;
    }

    /**
     * Collects internal links by pulling data from related posts (keywords-posts relation)
     * @param int $ideaId ID of Idea or Post to collect the links for
     * @param int $n Number of links, default 5
     * @return object Class instance
     */
    public function forIdea($ideaId = null, $n = 5, $useRandom = true)
    {
        $internalLinks = [];

        if (
            empty($ideaId)
            || !is_numeric($ideaId)
            || empty(SEOAIC_SETTINGS::isGenerateInternalLinksEnabled())
        ) {
            return $this;
        }

        $getKeywordsPageLinks = function ($keywords) {
            return array_map(
                function ($mapItem) {
                    return $mapItem['page_link'];
                },
                array_filter($keywords, function ($filterItem) {
                    return !empty($filterItem['page_link']);
                })
            );
        };

        $ideaKeywords_WPPosts = KeywordsPostsRelation::getKeywordsByPostId($ideaId);
        $ideaKeywords = $this->seoaic->keywords->convertFormatFromPostsToKeywords($ideaKeywords_WPPosts);
        $keywordsPagesLinks = $getKeywordsPageLinks($ideaKeywords);

        // 1-2 Keyword's Page links
        if (!empty($keywordsPagesLinks)) {
            if (2 < count($keywordsPagesLinks)) {
                shuffle($keywordsPagesLinks);
                $keywordsPagesLinks = array_slice($keywordsPagesLinks, 0, 2);
            }

            $keywordsPagesLinksIds = array_filter($keywordsPagesLinks, function ($item) {
                return is_numeric($item);
            });

            if (!empty($keywordsPagesLinksIds)) { // links of posts
                $keywordsPagesLinksPosts = get_posts([
                    'post_type'     => 'any',
                    'numberposts'   => -1,
                    'lang'          => '',
                    'include'       => $keywordsPagesLinksIds,
                    'meta_query' => [ // all posts, without hiding feature
                        'relation' => 'OR',
                        [
                            'key' => 'seoaic_posted',
                            'compare' => 'EXISTS'
                        ],
                        [
                            'key' => 'seoaic_posted',
                            'compare' => 'NOT EXISTS'
                        ],
                    ]
                ]);
                $internalLinks = array_merge($internalLinks, $keywordsPagesLinksPosts);
            }


            $keywordsPagesLinksCustom = array_filter($keywordsPagesLinks, function ($item) {
                return !is_numeric($item);
            });

            if (!empty($keywordsPagesLinksCustom)) { // custom links
                $internalLinks = array_merge($internalLinks, $keywordsPagesLinksCustom);
            }
        }

        // 3-4 Related Posts
        $ideaLanguage = $this->seoaic->multilang->get_post_language($ideaId);
        $ideaLanguageCode = $this->seoaic->multilang->get_post_language($ideaId, 'code');
        $relatedPostsAll = KeywordsPostsRelation::getRelatedPosts($ideaId);

        $relatedPosts = array_filter($relatedPostsAll, function ($item) use ($ideaLanguage) {
            $lang = $this->seoaic->multilang->get_post_language($item->ID);

            return $lang == $ideaLanguage;
        });

        if (!empty($relatedPosts)) {
            shuffle($relatedPosts);
            $internalLinks = array_merge($internalLinks, $relatedPosts);
            $internalLinks = $this->filterInternalLinks($internalLinks);

            if ($n < count($internalLinks)) {
                $internalLinks = array_slice($internalLinks, 0, $n);
            }
        }

        if (
            $useRandom
            && 0 == count($internalLinks)
        ) {
            $internalLinks = array_merge($internalLinks, $this->getRandomPosts($n, [], $ideaLanguageCode));
        }
        // if not enough related posts - add random
        // if ($n > count($internalLinks)) {
        //     $diffN = $n - count($internalLinks);
        //     $randomPosts = $this->getRandomPosts($diffN, array_map(function ($item) {
        //         return $item->ID;
        //     }, $internalLinks));
        //     $internalLinks = array_merge($internalLinks, $randomPosts);
        // }


        $this->internalLinks = $internalLinks;

        return $this;
    }

    /**
     * @param array $IDs IDs of the keywords
     * @param int $n Optional. Number of internal links to be made
     * @param string $type Type of internal links: ['all', 'post', 'idea']
     * @return object Class instance
     */
    public function forKeywords(array $IDs, int $n = null, string $type = 'all')
    {
        if (empty($IDs)) {
            return $this;
        }

        $internalLinks = [];

        $keywords = $this->seoaic->keywords->getKeywordsByIDs($IDs);

        if (
            !empty($keywords)
            && is_array($keywords)
        ) {
            foreach ($keywords as $keyword) {
                $pageLink = $keyword['page_link'];

                if (empty($pageLink)) {
                    continue;
                }

                if (is_numeric($pageLink)) { // post selected from list
                    $linkPost = get_post($pageLink);

                    if (!$linkPost) {
                        continue;
                    }

                    $internalLinks[] = $linkPost;

                } else { // custom url
                    $internalLinks[] = $keyword['page_link'];
                }
            }
        }

        $relatedPostsAll = [];

        foreach ($IDs as $id) {
            $keywordRelatedPosts = KeywordsPostsRelation::getPostsByKeywordId($id);

            if ('post' == $type) {
                $keywordRelatedPosts = array_filter($keywordRelatedPosts, function ($post) {
                    return SEOAIC_IDEAS::IDEA_STATUS != $post->post_status;
                });
            } else if ('idea' == $type) {
                $keywordRelatedPosts = array_filter($keywordRelatedPosts, function ($post) {
                    return SEOAIC_IDEAS::IDEA_STATUS == $post->post_status;
                });
            }

            if (
                !empty($keywordRelatedPosts)
                && is_array($keywordRelatedPosts)
            ) {
                $relatedPostsAll = array_merge($relatedPostsAll, $keywordRelatedPosts);
            }
        }

        if (!empty($relatedPostsAll)) {
            if (is_null($n)) {
                $internalLinks = $this->filterInternalLinks(array_merge($internalLinks, $relatedPostsAll));

            } else {
                shuffle($relatedPostsAll);
                $internalLinks = $this->filterInternalLinks(array_merge($internalLinks, $relatedPostsAll));

                if ($n < count($internalLinks)) {
                    $internalLinks = array_slice($internalLinks, 0, $n);
                }
            }
        }

        $this->internalLinks = $internalLinks;

        return $this;
    }

    /**
     * Get random posts
     * @param int $n Number of posts. Default 5.
     * @param int[] $excludeIDs Array of IDs to Exclude. Optional.
     * @param string $lang Language code to filter posts by. Optional.
     * @return array
     */
    public function random($n = 5, $excludeIDs = [], $lang = '')
    {
        $this->internalLinks = $this->getRandomPosts($n, $excludeIDs, $lang);

        return $this;
    }

    /**
     * @param array $posts Array of WP_Post-s with possible string item (custom link URL)
     * @return string
     */
    public static function makeInternalLinksPermalinkAndTitleString(array $posts): string
    {
        $links = [];

        if (!empty($posts)) {
            foreach ($posts as $post) {
                if (is_string($post)) {
                    $links[] = $post;
                } else if (!empty($post->ID)) {
                    $links[] = get_permalink($post->ID) . " - " . get_the_title($post->ID);
                }
            }

            return implode(', ', $links) . '.';
        }

        return '';
    }

    private function getRandomPosts($n = 5, $excludeIDs = [], $lang = ''): array
    {
        $args = array(
            'post_type'         => SEOAIC_SETTINGS::getSEOAICPostType(),
            'post_status'       => 'publish',
            'posts_per_page'    => $n,
            'orderby'           => 'rand',
            'ignore_sticky_posts' => 1,
            'meta_query'        => [
                [
                    'key'       => 'seoaic_posted',
                    'value'     => 1,
                    'compare'   => '='
                ]
            ]
        );

        if (!empty($excludeIDs)) {
            if (!is_array($excludeIDs)) {
                $excludeIDs = [$excludeIDs];
            }
            $args['post__not_in'] = $excludeIDs;
        }

        // $similar_posts = get_posts($args);
        $this->seoaic->multilang->preProcessPostsMainQuery($args, $lang);
        $query = new WP_Query($args);
        $similar_posts = $query->posts;
        $similar_posts_query = $this->seoaic->multilang->sort_posts_by_languages($similar_posts);

        if (!empty($similar_posts_query)) {
            return $similar_posts_query;
        }

        return [];
    }

    private function filterInternalLinks($links = [])
    {
        $links = empty($links) ? $this->internalLinks : $links;

        if (empty($links)) {
            return [];
        }

        $duplicateKeys = [];
        $tmp = [];

        foreach ($links as $key => $value) {
            if (is_object($value)) {
                $value = $value->ID;
            }

            if (!in_array($value, $tmp)) {
                $tmp[] = $value;
            } else {
                $duplicateKeys[] = $key;
            }
        }

        foreach ($duplicateKeys as $key) {
            unset($links[$key]);
        }

        return $links;
    }

    public static function convertFromMetaDataToString(array $data)
    {
        if (
            empty($data)
            || !is_array($data)
        ) {
            return '';
        }

        $links = [];

        foreach ($data as $item) {
            if (is_numeric($item)) {
                $post = get_post($item);

                if ($post) {
                    $links[] = $post;
                }

            } else {
                $links[] = $item;
            }
        }

        $formattedString = self::makeInternalLinksPermalinkAndTitleString($links);

        return $formattedString;
    }
}
