<?php

namespace Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Post\Traits;

use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\AutoLink;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Post\Post;
use Linksy\SearchAndReplace\Plugli\Linksy\Common\Helpers\Settings;
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Arr;
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Database\Database;
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Links;
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Str;
trait Link
{
    public function count_links(callable $cb = null, bool $is_internal = \true)
    {
        $q = Database::table('linksy_links')->selectCount('id', 'count')->where('is_internal', (int) $is_internal);
        if (is_callable($cb)) {
            $q = $cb($q);
        }
        return $q->getVar();
    }
    public function has_exceed_max_inbound_links()
    {
        $max_inbound_links = (int) Settings::get('max_inbound_links_per_post', -1);
        if ($max_inbound_links <= 0) {
            return \false;
        }
        return $max_inbound_links <= $this->count_links(function ($q) {
            return $q->where('to_post_id', $this->get_ID());
        });
    }
    public function has_exceed_max_outbound_links()
    {
        $max_outbound_links = (int) Settings::get('max_outbound_links_per_post', -1);
        if ($max_outbound_links <= 0) {
            return \false;
        }
        return $max_outbound_links <= $this->count_links(function ($q) {
            return $q->where('post_id', $this->get_ID());
        });
    }
    public function has_link_to($dest)
    {
        return 0 < $this->count_links(function ($q) use ($dest) {
            return $q->where('post_id', $this->get_ID())->where('to_post_id', $dest);
        });
    }
    public function verify_autolink_settings($link, $anchor, $links_cnt, $used_keywords, $used_links)
    {
        // ensure max total links is not exceeded
        if (isset($links_cnt[$anchor]) && $links_cnt[$anchor] >= (int) $link->max_total_links) {
            return \false;
        }
        // allow multiple anchors = 0
        if (!$link->allow_duplicate_anchors && in_array($anchor, $used_keywords)) {
            return \false;
        }
        // do not link to self
        if ($link->clean_url == $this->get_link() || $link->raw_url == $this->get_link()) {
            return \false;
        }
        if (!$link->allow_duplicate_links && in_array($link->raw_url, $used_links)) {
            return \false;
        }
        return \true;
    }
    public function get_anchor_tag($anchor, $url = null)
    {
        // get settings related to anchor creation
        $setting_open_internal_link_in_new_tab = Settings::get('open_internal_link_in_new_tab', \false);
        $add_destination_post_title_to_links = Settings::get('add_destination_post_title_to_links', \false);
        $tag = '<a href="' . ($url ? $url : $this->get_link()) . '"';
        if ($setting_open_internal_link_in_new_tab) {
            $tag .= ' target="_blank"';
        }
        if ($add_destination_post_title_to_links) {
            if (!$url) {
                $tag .= ' title="' . $this->get_title() . '"';
            } else {
                $post_id = url_to_postid($url);
                $post_id ? $tag .= ' title="' . (new Post($post_id))->get_title() . '"' : $tag;
            }
        }
        $tag .= '>' . $anchor . '</a>';
        return $tag;
    }
    public function delete_links(array $links, $check_autolink = \true)
    {
        $stats = ['deleted' => [], 'failed' => []];
        if (!$this->get_editor() || empty($links)) {
            return $stats;
        }
        if ($check_autolink) {
            $running_autolinks = Autolink::getRunningLinks();
            list($keywords, $urls) = [[], []];
            foreach ($running_autolinks as $link) {
                $keywords[] = Arr::get_value($link, 'keyword', 'strtolower');
                $urls[] = Arr::get_value($link, 'raw_url', 'strtolower');
            }
        }
        foreach ($links as $link) {
            $link = (object) $link;
            if ($check_autolink && in_array(strtolower($link->anchor), $keywords) && in_array(strtolower($link->view_link), $urls)) {
                $stats['failed'][] = $link->anchor;
                continue;
            }
            $success = $this->editor->remove_link($link->view_url, $link->anchor, \true);
            if (!empty($stats)) {
                $success ? $stats['deleted'][] = $link->anchor : $stats['failed'][] = $link->anchor;
                $this->refresh_links();
                $this->delete_broken_links();
            }
        }
        if ($this->editor->has_unsaved_changes()) {
            $this->editor->update_post();
        }
        return $stats;
    }
    public function replace_links(array $links, $replace = \false, $check_autolink = \true)
    {
        $stats = ['replaced' => [], 'failed' => []];
        if (!$this->get_editor() || empty($links)) {
            return $stats;
        }
        if ($check_autolink) {
            $autolinks = array_map(function ($link) {
                return $link->keyword;
            }, AutoLink::getRunningLinks());
        }
        foreach ($links as $link) {
            $link = (object) $link;
            if ($check_autolink && in_array($link->anchor, $autolinks)) {
                $stats['failed'][] = $link->anchor;
                continue;
            }
            if ($replace) {
                $success = $this->editor->replace_phrase($link->view_url, $link->anchor, $link->link_replacement, \false);
            }
            if (!empty($stats)) {
                $success ? $stats['replaced'][] = $link->anchor : $stats['failed'][] = $link->anchor;
            }
        }
        if ($this->editor->has_unsaved_changes()) {
            $this->editor->update_post();
        }
        return $stats;
    }
    public function refresh_links()
    {
        $anchors = $this->get_content_links();
        $old_links = Database::table("linksy_links")->where('post_id', $this->get_ID())->select(['anchor', 'to_post_id', 'score'])->get();
        Database::table("linksy_links")->where('post_id', $this->get_ID())->delete();
        $data = [];
        foreach ($anchors as $a) {
            $link = ['post_id' => $this->get_ID(), 'post_type' => $this->get_type(), 'post_title' => $this->get_title(), 'raw_url' => $a['link'], 'clean_url' => esc_url_raw($a['link']), 'anchor' => $a['text'], 'to_post_id' => $a['to_post_id'], 'is_internal' => $a['is_internal'], 'is_broken' => $a['is_broken'], 'aria_label' => $a['aria_label'], 'target_attribute' => $a['target_attribute'], 'rel' => $a['rel'], 'host' => $a['host'], 'meta' => wp_json_encode($a['meta']), 'score' => 'null'];
            $old_links_index = \false;
            foreach ($old_links as $k => $v) {
                if ($v->anchor == $a['text'] && $v->to_post_id == $a['to_post_id']) {
                    $old_links_index = $k;
                    break;
                }
            }
            if ($old_links_index !== \false) {
                $link['score'] = $old_links[$old_links_index]->score;
            }
            $data[] = $link;
        }
        if (count($data)) {
            Database::table("linksy_links")->insertMultiple(['post_id', 'post_type', 'post_title', 'raw_url', 'clean_url', 'anchor', 'to_post_id', 'is_internal', 'is_broken', 'aria_label', 'target_attribute', 'rel', 'host', 'meta', 'score'], $data);
        } else {
            return \false;
        }
        return \true;
    }
    public function delete_broken_links()
    {
        $deleted = Database::table("linksy_broken_links")->where('post_id', $this->get_ID())->delete();
        return $deleted;
    }
    public function get_content_links()
    {
        $this_link = wp_parse_url(get_site_url());
        $the_content = $this->get_content();
        if (empty($the_content)) {
            return [];
        }
        $report_links = [];
        $anchors = Links::extract_from_html_dom($the_content);
        $base_url = home_url('/');
        // get the homepage url
        foreach ($anchors as $a) {
            if (!empty($a['link'])) {
                $parsed_href = wp_parse_url($a['link']);
                $is_not_a_real_anchor = !isset($parsed_href['host']) || empty($parsed_href['host']);
                if ($is_not_a_real_anchor) {
                    if (empty($parsed_href['path']) || !empty($parsed_href['scheme'])) {
                        continue;
                    }
                    $parsed_href['host'] = $this_link['host'];
                }
                if ($parsed_href['host'] == $this_link['host']) {
                    $report_link = ['is_internal' => 1];
                    $to_post_id = url_to_postid($a['link']);
                    // set to_post_id if not zero
                    $report_link['to_post_id'] = $to_post_id == 0 ? null : $to_post_id;
                    if ($to_post_id == 0 && $a['link'] != $base_url) {
                        $report_link['is_broken'] = 1;
                    } else {
                        $report_link['is_broken'] = 0;
                    }
                    $report_links[] = array_merge($a, $report_link, ['host' => $parsed_href['host']]);
                } else {
                    $report_links[] = array_merge($a, ['is_broken' => 0, 'is_internal' => 0, 'to_post_id' => null, 'host' => $parsed_href['host']]);
                }
            }
        }
        return $report_links;
    }
    public function get_linksy_links($type = 'all')
    {
        $inbound_links = [];
        $outbound_links = [];
        $external_links = [];
        $ignore_image_urls = Settings::get('ignore_image_urls', \false);
        $q = Database::table("linksy_links");
        if ($type === 'inbound') {
            $q = $q->where('to_post_id', $this->get_ID());
        } else if ($type === 'all') {
            $q = $q->where('post_id', $this->get_ID())->orWhere('to_post_id', $this->get_ID());
        } else {
            $q = $q->where('is_internal', (int) $type === 'outbound');
        }
        $anchors = $q->get();
        foreach ($anchors as $a) {
            $a_meta = json_decode($a->meta);
            $a->clean_anchor = trim(Str::strip_tags($a->anchor));
            if ($ignore_image_urls) {
                if (!empty($a_meta) && (int) $a_meta->is_image_url) {
                    continue;
                }
            }
            if ($a->to_post_id == $this->post->ID) {
                $inbound_links[] = $a;
            } else if ($a->is_internal) {
                $outbound_links[] = $a;
            } else {
                $external_links[] = $a;
            }
        }
        return ['inbound_links' => $inbound_links, 'outbound_links' => $outbound_links, 'external_links' => $external_links];
    }
}
