<?php
/**
 * Prohibit direct script loading
 */
defined('ABSPATH') || die('No direct script access allowed!');

/**
 * Class WpmsGscIssues
 */
class WpmsGscIssues
{
    /**
     * Options
     *
     * @var string
     */
    private $opt = '';
    /**
     * List of all current issues to compare with received issues
     *
     * @var array
     */
    private $wpms_current_issues = array();
    /**
     * Holder for all the issues
     *
     * @var array|mixed|void
     */
    private $issues = array();

    /**
     * WpmsGscIssues constructor.
     * Setting up the properties and fetching the current issues
     *
     * @param string  $plat           Platform
     * @param string  $cat            Category
     * @param boolean $fetched_issues Fetched issues
     */
    public function __construct($plat, $cat, $fetched_issues = false)
    {
        $this->opt    = strtolower('wpms-gsc-issues-' . $plat . '-' . $cat);
        $this->issues = $this->getIssues();

        if (!empty($fetched_issues) && is_array($fetched_issues)) {
            $this->saveFetchedIssues($fetched_issues);
        }
    }

    /**
     * Fetching the issues for current category and compare them with the already existing issues.
     *
     * @param array $lists Set of retrieved issues.
     *
     * @return void
     */
    private function saveFetchedIssues(array $lists)
    {
        $this->setCurrentIssues();
        $issues = $this->getIssues();
        foreach ($lists as $issue) {
            $this->issueCompare($issues, $issue);
        }

        $this->saveIssues($issues);
        // Refresh value
        $this->issues = $this->getIssues();
    }

    /**
     * Getting the issues from the options.
     *
     * @return mixed
     */
    public function getIssues()
    {
        return get_option($this->opt, array());
    }

    /**
     * Deleting the issue from the issues
     *
     * @param string $url URL to delete issues for.
     *
     * @return boolean
     */
    public function removeIssue($url)
    {
        $target_issue = $this->getIssueByLink($url);
        if ($target_issue !== false) {
            unset($this->issues[$target_issue]);
            // save issues
            $this->saveIssues($this->issues);

            return true;
        }

        return false;
    }

    /**
     * Comparing the issue with the list of current existing issues
     *
     * @param array    $crawl_issues Set of issues by reference.
     * @param stdClass $issue        Issue object to check against the list.
     *
     * @return void
     */
    private function issueCompare(&$crawl_issues, $issue)
    {
        $issue->pageUrl = WPMSUtils::formatUrl((string) $issue->pageUrl);
        if (!in_array($issue->pageUrl, $this->wpms_current_issues)) {
            array_push($crawl_issues, $this->getIssue($this->createIssue($issue)));
        }
    }

    /**
     * Returns the crawl issue as an array.
     *
     * @param WpmsGscIssue $crawl_issue Issue object instance.
     *
     * @return array
     */
    private function getIssue(WpmsGscIssue $crawl_issue)
    {
        $issue = $crawl_issue->toArray();
        return $issue;
    }

    /**
     * The fetched issue from the API will be parsed as an WPSEO_Crawl_Issue object. After initializing the issue as an
     * object, the object will be returned
     *
     * @param stdClass $issue Issue data object.
     *
     * @return WpmsGscIssue
     */
    private function createIssue($issue)
    {
        $new_issue = new WpmsGscIssue(
            $issue->pageUrl,
            new DateTime((string) $issue->first_detected),
            new DateTime((string) $issue->last_crawled),
            (string) (!empty($issue->responseCode)) ? $issue->responseCode : null
        );
        return $new_issue;
    }

    /**
     * Search in the issues for the given $url
     *
     * @param string $url Issue URL to search for.
     *
     * @return integer|string
     */
    private function getIssueByLink($url)
    {
        foreach ($this->issues as $key => $issue) {
            if ($url === $issue['url']) {
                return $key;
            }
        }

        return false;
    }

    /**
     * Saving the issues to the options. The target option is base on current platform and category.
     *
     * @param array $issues Set of issues.
     *
     * @return void
     */
    private function saveIssues(array $issues)
    {
        update_option($this->opt, $issues, false);
    }

    /**
     * Getting the issues from the options and get only the URL out of it. This is because there will be a comparison
     * with the issues from the API.
     *
     * @return void
     */
    private function setCurrentIssues()
    {
        if (!empty($this->issues)) {
            $this->wpms_current_issues = wp_list_pluck($this->issues, 'url');
        }
    }
}
