<?php
// Silence may be golden, but sometimes words paint the canvas of understanding.

namespace Plugli\Linksy\SearchAndReplace\Admin\Partials\SearchAndReplace\Helpers;

use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Arr;
use Plugli\Linksy\SearchAndReplace\Helpers\Post\Post;
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Database\Database;
use Linksy\SearchAndReplace\Plugli\Standard\Helpers\Str;

class AnchorReplace extends Helpers
{
    protected $search_type;

    public function get($search_mode, $filter_query, $options = [])
    {
        $links = Database::table("linksy_links");

        $this->search_type = $search_mode;

        switch ($search_mode) {
            case 'EXACT':
                $links = $links->where('anchor', $this->search);
                break;
            case 'ANCHOR_CONTAINS':
                $links = $links->whereLike('anchor', $this->search);
                break;
            case 'EMPTY_ANCHOR':
                $links = $links->whereIn('anchor', ['', ' ']);
                break;
            case 'STARTS_WITH':
                $links = $links->where('anchor', 'like', $this->search . '%');
                break;
            case 'ENDS_WITH':
                $links = $links->where('anchor', 'like', '%' . $this->search);
                break;
            case 'COMMA_AFTER':
                $links = $links->where('anchor', 'like', '%' . ',');
                break;
            case 'COMMA_BEFORE':
                $links = $links->where('anchor', 'like', ',' . '%');
                break;
            case 'SPACE_AFTER':
                $links = $links->where('anchor', 'like', '%' . ' ');
                break;
            case 'SPACE_BEFORE':
                $links = $links->where('anchor', 'like', ' ' . '%');
                break;
            case 'FULL_STOP_AFTER':
                $links = $links->where('anchor', 'like', '%' . '.');
                break;
            case 'FULL_STOP_BEFORE':
                $links = $links->where('anchor', 'like', '.' . '%');
                break;
        }

        $links = $links->get();
        $data = [];

        foreach ($links as $link) {
            if ($search_mode === 'SHARED_TARGET') {
                $key = $link->post_id . "_{$link->clean_url}";
            } elseif ($search_mode === 'DUPLICATE') {
                $key = $link->post_id . "_{$link->anchor}";
            }
            
            $post = new Post($link->post_id);

            if ($search_mode === 'SHARED_TARGET' || $search_mode === 'DUPLICATE') {
                $this->handleDataByKey($data, $link, $post, $key);
            } else {
                $this->handleDataByDefault($data, $link, $post);
            }
        }

        if ($search_mode === 'SHARED_TARGET' || $search_mode === 'DUPLICATE') {
            $data = Arr::filter(
                $data,
                function ($item) {
                    return count($item['anchors']) >= 2;
                },
                true
            );
        }

        foreach ($data as &$item) {
            if (isset($item['sources']) && is_array($item['sources'])) {
                $item['sources'] = array_values($item['sources']);
            }
        }
        unset($item);

        if (!empty($this->filters['search_mode'])) {
            return $this->filter($data);
        }

        return $data;
    }

    public function filter($data = [], $query = '')
    {
        if (empty($this->filters) || empty($this->filters['search_mode'])) {
            return $data;
        }

        $filteredData = $data;

        foreach ($this->filters['search_mode'] as $mode) {
            switch ($mode) {
                case 'link-is':
                    $query = $this->filters['link'] ?? '';
                    break;
                case 'source-is':
                    $query = $this->filters['source'] ?? '';
                    break;
                default:
                    $query = $this->filters[$mode] ?? '';
                    break;
            }

            if ($query === '') {
                continue;
            }

            $tempFilteredData = [];
            $this->filter_mode = $mode;

            foreach ($filteredData as $key => $item) {
                if ($this->search_type === 'SHARED_TARGET' || $this->search_type === 'DUPLICATE') {
                    $updatedItem = $this->filterByMode($item, $query);
                } else {
                    $updatedItem = $this->filterByModeDefault($item, $query);
                }

                if ($updatedItem) {
                    $tempFilteredData[$key] = $updatedItem;
                }
            }

            $filteredData = $tempFilteredData;
        }

        return array_values($filteredData);
    }

    protected function filterByModeDefault($item, $query)
    {
        $anchor = $item['anchor'] ?? '';

        if ($this->filter_mode === 'anchor') {
            if (Str::contains(strtolower($anchor), strtolower($query))) {
                return $item;
            }
            return false;
        }

        if ($this->filter_mode === 'link' || $this->filter_mode === 'link-is') {
            $exactMatch = ($this->filter_mode === 'link-is');
            
            $matchingSources = [];
            foreach ($item['sources'] as $source) {
                $matchingLinks = Arr::filter(
                    $source['links'] ?? [],
                    function ($linkData) use ($query, $exactMatch) {
                        if (!isset($linkData['link'])) {
                            return false;
                        }
                        $link = strtolower($linkData['link']);
                        $lowerQuery = strtolower($query);

                        return $exactMatch ? ($link === $lowerQuery) : Str::contains($link, $lowerQuery);
                    }
                );

                if (count($matchingLinks)) {
                    $source['links'] = $matchingLinks;
                    $matchingSources[] = $source;
                }
            }

            if (count($matchingSources)) {
                $item['sources'] = $matchingSources;
                return $item;
            }
            return false;
        }

        if ($this->filter_mode === 'source' || $this->filter_mode === 'source-is') {
            $exactMatch = ($this->filter_mode === 'source-is');
            $matchingSources = Arr::filter(
                $item['sources'],
                function ($source) use ($query, $exactMatch) {
                    if (!isset($source['source'])) {
                        return false;
                    }
                    $sourceValue = strtolower($source['source']);
                    $lowerQuery = strtolower($query);

                    return $exactMatch ? ($sourceValue === $lowerQuery) : Str::contains($sourceValue, $lowerQuery);
                }
            );

            if (count($matchingSources)) {
                $item['sources'] = $matchingSources;
                return $item;
            }
            return false;
        }

        return false;
    }

    protected function filterByMode($item, $query)
    {
        if ($this->filter_mode === 'anchor') {
            $matchingAnchors = Arr::filter(
                $item['anchors'] ?? [],
                function ($anchorData) use ($query) {
                    return isset($anchorData['anchor']) && Str::contains(strtolower($anchorData['anchor']), strtolower($query));
                }
            );

            if (count($matchingAnchors)) {
                $item['anchors'] = $matchingAnchors;
                return $item;
            }

            return false;
        }

        if ($this->filter_mode === 'link' || $this->filter_mode === 'link-is') {
            $exactMatch = ($this->filter_mode === 'link-is');

            $matchingAnchors = Arr::filter(
                $item['anchors'] ?? [],
                function ($anchorData) use ($query, $exactMatch) {
                    if (!isset($anchorData['link'])) {
                        return false;
                    }
                    $link = strtolower($anchorData['link']);
                    $lowerQuery = strtolower($query);

                    return $exactMatch ? ($link === $lowerQuery) : Str::contains($link, $lowerQuery);
                }
            );

            if (count($matchingAnchors)) {
                $item['anchors'] = $matchingAnchors;
                return $item;
            }

            return false;
        }

        if ($this->filter_mode === 'source' || $this->filter_mode === 'source-is') {
            $exactMatch = ($this->filter_mode === 'source-is');

            if (isset($item['source'])) {
                $source = strtolower($item['source']);
                $lowerQuery = strtolower($query);

                if ($exactMatch ? ($source === $lowerQuery) : Str::contains($source, $lowerQuery)) {
                    return $item;
                }
            }
            return false;
        }

        return false;
    }

    protected function handleDataByKey(array &$data, $link, $post, $key)
    {
        if (!isset($data[$key])) {
            $data[$key] = [
                'source' => $link->post_title,
                'post_id' => $link->post_id,
                'to_post_id' => $link->to_post_id,
                'view_link' => $post->get_link(),
                'edit_link' => $post->get_edit_link(),
                'anchors' => []
            ];
        }
    
        $data[$key]['anchors'][] = [
            'anchor' => $link->anchor,
            'score' => $link->score,
            'link' => $link->clean_url,
        ];
    }
    
    function handleDataByDefault(array &$data, $link, $post): void {
        $anchor = $link->anchor;
        $postId = $link->post_id;

        if (!isset($data[$anchor])) {
            $data[$anchor] = [
                'anchor' => $anchor,
                'sources' => []
            ];
        }
    
        if (!isset($data[$anchor]['sources'][$postId])) {
            $data[$anchor]['sources'][$postId] = [
                'source' => $link->post_title,
                'post_id' => $link->post_id,
                'to_post_id' => $link->to_post_id,
                'edit_link' => $post->get_edit_link(),
                'view_link' => $post->get_link(),
                'links' => []
            ];
        }
    
        $data[$anchor]['sources'][$postId]['links'][] = [
            'link' => $link->clean_url,
            'score' => $link->score,
        ];
    }
}
