<?php

// Silence may be golden, but sometimes words paint the canvas of understanding.
namespace Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Post;

/**
 * Hadndle post object.
 *
 * @since      1.0.1
 * @package    Linksy
 * @subpackage Linksy\admin
 * @author     Gbenga Medunoye <laxusgooee@gmail.com>
 */
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Arr;
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\External\Encoding;
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Database\Database;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Keywords\Keywords;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Settings;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\AutoLink;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Post\Traits\Editor;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Post\Traits\Link;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Post\Traits\Suggestion;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Utils;
/**
 * Post class.
 */
class Post
{
    use Editor;
    use Suggestion;
    use Link;
    private $post;
    public $editor = null;
    public $editor_namespace = null;
    private $is_loaded = \false;
    private $tags = null;
    private $categories = null;
    private $settings = null;
    function __construct($post, $pre_load = \false)
    {
        $this->post = is_numeric($post) ? (object) ['ID' => $post] : (object) $post;
        if ($pre_load) {
            $this->load_post();
        }
        $this->set_editor_namespace();
    }
    private function load_post()
    {
        $this->is_loaded = \true;
        $this->post = get_post($this->get_ID());
    }
    public function set_editor_namespace()
    {
        $this->editor_namespace = 'Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Post\Editors';
    }
    public function get_ID()
    {
        return $this->post->ID;
    }
    public function exists()
    {
        return Database::table('posts')->where('ID', $this->get_ID())->selectCount()->getVar() > 0;
    }
    public function get_title()
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        return Encoding::toUTF8($this->post->post_title);
    }
    public function get_type()
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        return $this->post->post_type;
    }
    public function get_date($format = '')
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        return get_the_date($format, $this->get_ID());
    }
    public function get_date_modified($format = '')
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        return get_the_modified_date($format, $this->get_ID());
    }
    public function get_link()
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        return get_permalink($this->get_ID());
    }
    public function get_edit_link($context = '')
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        return get_edit_post_link($this->get_ID(), $context);
    }
    public function get_categories()
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        if (is_null($this->categories)) {
            $this->categories = get_the_category($this->get_ID());
        }
        return is_array($this->categories) ? $this->categories : [];
    }
    public function get_tags()
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        if (is_null($this->tags)) {
            $tags = get_the_tags($this->get_ID());
            if ($tags !== \false) {
                $this->tags = $tags;
            }
        }
        return is_array($this->tags) ? $this->tags : [];
    }
    public function run_autolinks($keywords = [])
    {
        if (!$this->is_suggestable(['max_inbound_links_per_post'])) {
            return \false;
        }
        // filter out autolinks that do not support this post type
        $running_links = AutoLink::getRunningLinks($keywords, function ($q) {
            return $q->select(['post_categories', 'post_tags', 'is_same_category', 'is_same_tag']);
        });
        $autolinks = Arr::filter($running_links, function ($link) {
            $post_types = Arr::get_value($link, 'post_types');
            return in_array($this->get_type(), Arr::split($post_types, ',', Settings::get('suggestions_post_types', ['post', 'page'])));
        });
        if (empty($autolinks)) {
            return \false;
        }
        // extract the keywords from the autolinks
        $extracted_keywords = array_map(function ($link) {
            return strtolower($link->keyword);
        }, $autolinks);
        // get links count for the extracted keywords
        $links_cnt = AutoLink::getLinksCount($extracted_keywords);
        // get links from linksy_links table with this post as source
        $linksy_links = Database::table("linksy_links")->select(['anchor', 'to_post_id', 'raw_url'])->where('post_id', $this->get_ID())->get();
        // extract used keywords and links
        $used_keywords = array_map(function ($l) {
            return Arr::get_value($l, 'anchor', 'strtolower');
        }, $linksy_links);
        $used_links = array_map(function ($l) {
            return Arr::get_value($l, 'raw_url');
        }, $linksy_links);
        // get keywords ranges from this post suggestable content
        $ranges = Keywords::get_keywords_range($extracted_keywords, $this->get_suggestable_content(\false, ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'img']), ['allow_multiple' => 1]);
        $suggestions = [];
        foreach ($ranges as $range) {
            // get range link
            $link = Arr::find(function ($link) use ($range) {
                $keyword = Arr::get_value($link, 'keyword');
                $is_case_sensitive = Arr::get_value($link, 'is_case_sensitive', 'boolval');
                if ($is_case_sensitive) {
                    return $keyword === $range['phrase'];
                }
                return strtolower($keyword) === strtolower($range['phrase']);
            }, $autolinks);
            if (is_null($link)) {
                continue;
            }
            $has_categories = !empty($link->post_categories);
            $has_tags = !empty($link->post_tags);
            if ($link->is_same_category && (!$has_categories || count($this->get_categories()) === 0) || $link->is_same_tag && (!$has_tags || count($this->get_tags()) === 0)) {
                continue;
            }
            if ($link->is_same_category && !$this->has_category(json_decode($link->post_categories))) {
                continue;
            }
            if ($link->is_same_tag && !$this->has_tag(json_decode($link->post_tags))) {
                continue;
            }
            $anchor = $link->is_case_sensitive ? $link->keyword : strtolower($link->keyword);
            if (!$this->verify_autolink_settings($link, $anchor, $links_cnt, $used_keywords, $used_links)) {
                continue;
            }
            $suggestions[] = ['phrase' => $range['phrase'], 'source' => $range['source'], 'post_title' => "autolink", 'replacement' => $this->get_anchor_tag($range['phrase'], $link->clean_url)];
            // increase the link count for this anchor
            $links_cnt[$anchor] = isset($links_cnt[$anchor]) ? $links_cnt[$anchor] + 1 : 1;
            // update used keywords and links
            $used_keywords[] = $anchor;
            $used_links[] = Arr::get_value($link, 'raw_url');
        }
        return $this->apply_suggestions($suggestions);
    }
    public function update_title(string $new_title)
    {
        if (strlen($new_title) === 0) {
            return \false;
        }
        $result = wp_update_post(['ID' => $this->get_ID(), 'post_title' => $new_title]);
        return $result !== 0;
    }
    /**
     * Updates the titles of an array of posts.
     * NOTE: Because this function violates SRP (Single Responsibility Principle) requirement,
     * it has been deprecated and will be removed in future versions of this library.
     * 
     * @param array $post_titles
     * @return array
     * 
     * @deprecated 1.0.1 Use update_title($new_title) instead
     */
    public function replace_post_titles(array $post_titles): array
    {
        $stats = ['replaced' => [], 'failed' => []];
        foreach ($post_titles as $post_title) {
            $post_id = $post_title['post_id'];
            $title_replacement = $post_title['new_title'];
            // Check if the post ID and replacement title are provided
            if (empty($post_id) || empty($title_replacement)) {
                continue;
            }
            // Update the post title using wp_update_post
            $post_update_args = ['ID' => $post_id, 'post_title' => $title_replacement];
            $result = wp_update_post($post_update_args);
            if (is_int($result) && $result !== 0) {
                $stats['replaced'][] = $post_id;
            } else {
                $stats['failed'][] = $post_id;
            }
        }
        return $stats;
    }
    public function get_keywords()
    {
        return Database::table('linksy_keywords')->select(['keyword', 'score', 'provider', 'is_ai_generated'])->where('post_id', $this->get_ID())->get(\ARRAY_A);
    }
    public function get_settings($key = null)
    {
        if (is_null($this->settings)) {
            $settings = Database::table("postmeta")->whereLike('meta_key', 'linksy_', '')->whereNotIn('meta_key', ['linksy_focus_keyword'])->where('post_id', $this->post->ID)->select(['meta_key', 'meta_value'])->get();
            $res = [];
            foreach ($settings as $item) {
                $res[$item->meta_key] = $item->meta_value;
            }
            $this->settings = $res;
        }
        if (!empty($key) && !empty($this->settings)) {
            return $this->settings['linksy_' . ltrim($key, 'linksy_')];
        }
        return is_array($this->settings) ? $this->settings : [];
    }
    public function get_post_language($save = \true)
    {
        $post_id = $this->get_ID();
        $postmeta = Database::table("linksy_postmeta")->where('post_id', $post_id);
        $post_language = $postmeta->select(['language_code'])->one();
        $multilingual_plugin = Settings::get('multilingual_plugin', 'none');
        $language = Settings::get('site_language', 'en');
        $language_code = !empty($post_language) ? $post_language->language_code : $language;
        switch ($multilingual_plugin) {
            case 'polylang':
                if (function_exists('Linksy\SearchAndReplace\pll_get_post_language')) {
                    $language = pll_get_post_language($post_id, 'slug');
                }
                break;
            case 'wpml':
                if (function_exists('Linksy\SearchAndReplace\apply_filters')) {
                    $language_info = apply_filters('wpml_post_language_details', null, $post_id);
                    if (!empty($language_info) && isset($language_info['language_code'])) {
                        $language = $language_info['language_code'];
                    }
                }
                break;
            case 'flexi':
                if (!empty($post_language)) {
                    $language = $language_code;
                }
                break;
        }
        if ($language_code !== $language && $save) {
            $language_list = Utils::json_file_decode(LINKSY_PLUGIN_DIR . '/linksy-languages.json');
            if (isset($language_list[$language])) {
                $language_name = $language_list[$language];
            } else {
                $language_name = 'Others';
            }
            if (!empty($post_language)) {
                if ($post_language->language_code !== $language || $post_language->language_name !== $language_name) {
                    $postmeta->set('language_code', $language)->set('language_name', $language_name)->update();
                }
            } else {
                Database::table("linksy_postmeta")->insert(['post_id' => $post_id, 'language_code' => $language, 'language_name' => $language_name]);
            }
        }
        return $language;
    }
    public function has_category($categories)
    {
        if (!is_array($categories)) {
            $categories = [$categories];
        }
        $is_in_category = \false;
        $the_post_categories = array_map(function ($cat) {
            return $cat->cat_ID;
        }, $this->get_categories());
        foreach ($the_post_categories as $category) {
            if (in_array($category, $categories)) {
                $is_in_category = \true;
                break;
            }
        }
        return $is_in_category;
    }
    public function has_tag($tags)
    {
        if (!is_array($tags)) {
            $tags = [$tags];
        }
        $is_in_tag = \false;
        $the_post_tags = array_map(function ($tag) {
            return $tag->term_id;
        }, $this->get_tags());
        foreach ($the_post_tags as $tag) {
            if (in_array($tag, $tags)) {
                $is_in_tag = \true;
                break;
            }
        }
        return $is_in_tag;
    }
    public function is_ignored($ignored_list)
    {
        return !empty($ignored_list) && in_array($this->get_link(), $ignored_list);
    }
    public function has_ignored_category($ignored_categories)
    {
        return !empty($ignored_categories) && $this->has_category($ignored_categories);
    }
    public function is_published()
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        return isset($this->post->post_status) && $this->post->post_status == 'publish';
    }
    public function is_before($date, $format = '')
    {
        return strtotime($this->get_date($format)) < strtotime($date);
    }
    public function is_after($date, $format = '')
    {
        return strtotime($this->get_date($format)) > strtotime($date);
    }
    public function to_post()
    {
        if (!$this->is_loaded) {
            $this->load_post();
        }
        return $this->post;
    }
}
