<?php

namespace SEOAIC\repositories;

use Exception;
use SEOAIC\content_improvement_suggestions\BrokenLinks;
use SEOAIC\content_improvement_suggestions\DescriptionToContentConsistency;
use SEOAIC\content_improvement_suggestions\DuplicateContent;
use SEOAIC\content_improvement_suggestions\DuplicateDescription;
use SEOAIC\content_improvement_suggestions\DuplicateTitle;
use SEOAIC\content_improvement_suggestions\IrrelevantDescription;
use SEOAIC\content_improvement_suggestions\IrrelevantTitle;
use SEOAIC\content_improvement_suggestions\TitleToContentConsistency;
use SEOAIC\content_improvement_suggestions\TitleTooLong;
use SEOAIC\content_improvement_suggestions\TitleTooShort;
use WP_Post;

class ContentImprovementSuggestionsRepository
{
    const CI_POST_ISSUES_FIELD = 'seoaic_ci_post_issues';

    // when an issue was obtained but not sent the suggestion request yet
    const CI_POST_ISSUE_STATUS_PENDING = 'pending';
    // when an issue was obtained and the suggestion request is sent already
    const CI_POST_ISSUE_STATUS_REQUESTED = 'requested';
    // when an issue was obtained but got the suggestion response
    const CI_POST_ISSUE_STATUS_COMPLETED = 'completed';
    const CI_POST_ISSUE_STATUS_ACCEPTED = 'accepted';
    const CI_POST_ISSUE_STATUS_REJECTED = 'rejected';

    private $seoaic;

    public function __construct($_seoaic)
    {
        $this->seoaic = $_seoaic;
    }

    private static function initInstances()
    {
        return [
            new BrokenLinks(),
            new DescriptionToContentConsistency(),
            new DuplicateContent(),
            new DuplicateDescription(),
            new DuplicateTitle(),
            new IrrelevantDescription(),
            new IrrelevantTitle(),
            new TitleToContentConsistency(),
            new TitleTooLong(),
            new TitleTooShort(),
        ];
    }

    public function getAll(): array
    {
        $instances = self::initInstances();
        $updInstances = [];

        foreach ($instances as $instance) {
            $updInstances[$instance->getId()] = $instance;
        }

        return $updInstances;
    }

    public function getById(string $id)
    {
        $instances = $this->getAll();
        $suggestionsKeys = array_keys($instances);

        if (in_array($id, $suggestionsKeys)) {
            return $instances[$id];
        }

        return null;
    }

    public function getForPost(WP_Post $post)
    {
        $postIssuesData = [];
        $availableSuggestions = $this->getAll();
        $savedIssues = $this->getSavedPostIssues($post);
        $postNewIssues = $this->getPostIssues($post);
        // error_log('savedIssues '.print_r($savedIssues, true));
        // error_log('$postNewIssues '.print_r($postNewIssues, true));

        if (
            empty($savedIssues)
            || $savedIssues['audit_date'] != $postNewIssues['audit_date']
        ) {
            // filter the issues to the ones that we can take care of
            // and which value should be fixed
            $filteredIssues = array_filter($postNewIssues['issues'], function ($value, $key) use ($availableSuggestions) {
                foreach ($availableSuggestions as $suggestion) {
                    if (
                        $key === $suggestion->getId()
                        && $suggestion->issueShouldBeFixed($value)
                    ) {
                        return true;
                    }
                }
            }, ARRAY_FILTER_USE_BOTH);
            // error_log('filteredIssues '.print_r($filteredIssues, true));
            $issues = array_map(
                function ($key, $value) use ($availableSuggestions) {
                    $status = self::CI_POST_ISSUE_STATUS_PENDING;

                    foreach ($availableSuggestions as $suggestion) {
                        if ( // mark issues which we can't generate a suggestion for as a completed ones
                            $key === $suggestion->getId()
                            && !$suggestion->canGenerateSuggestion
                        ) {
                            $status = self::CI_POST_ISSUE_STATUS_COMPLETED;
                            break;
                        }
                    }

                    return [
                        'issue'     => $key,
                        'status'    => $status,
                    ];
                },
                array_keys($filteredIssues),
                array_values($filteredIssues)
            );

            $postIssuesData = [
                'audit_date'    => $postNewIssues['audit_date'],
                'issues'        => $issues,
            ];
            $this->savePostIssues($post, $postIssuesData);

        } else {
            $postIssuesData = $savedIssues;
        }

        // add Suggestion object
        $suggestions = array_map(function ($item) use ($availableSuggestions) {
            // error_log('item '.print_r($item, true));
            foreach ($availableSuggestions as $suggestion) {
                if ($item['issue'] == $suggestion->getId()) {
                    $item['suggestion'] = $suggestion;
                }
            }

            return $item;
        }, $postIssuesData['issues']);

        return $suggestions;
    }

    public function getSavedPostIssues(WP_Post $post): Array {
        $savedIssues = get_post_meta($post->ID, self::CI_POST_ISSUES_FIELD, true);

        if (!empty($savedIssues)) {
            $savedIssues = maybe_unserialize($savedIssues);

            return $savedIssues;
        }

        return [];
    }

    public function getPostIssues(WP_Post $post): Array {
        try {
            $data = [
                'url' => get_permalink($post),
            ];

            $response = $this->seoaic->curl->withValidation(true)->initWithReturn('api/audit/page', $data, true, true);

            if (
                empty($response['audit'])
                || empty($response['auditInfoPages'][0])
            ) {
                throw new Exception(esc_html__("Empty audit info." , "seoaic"));
            }

            $checks = !empty($response['auditInfoPages'][0]['checks']) ? $response['auditInfoPages'][0]['checks'] : [];
            $customChecks = !empty($response['auditInfoPages'][0]['custom_checks']) ? $response['auditInfoPages'][0]['custom_checks'] : [];

            return [
                'audit_date' => wp_date("Y-m-d H:i:s", strtotime($response['audit']['created_at'])),
                'issues' => array_merge($checks, $customChecks),
            ];

        } catch (Exception $e) {
            throw new Exception(esc_html($e->getMessage()));
        }

        return [];
    }

    public function savePostIssues(WP_Post $post, array $postIssuesData): bool
    {
        $result = update_post_meta($post->ID, self::CI_POST_ISSUES_FIELD, $postIssuesData);

        return !!$result;
    }

    public function removePostIssues(WP_Post $post)
    {
        delete_post_meta($post->ID, self::CI_POST_ISSUES_FIELD);
    }
}
