<?php

namespace WPSN\Modules\AIReadiness;

use WPSN\Core\Branding;
use WPSN\Core\Container;
use WPSN\Core\Settings;

defined('ABSPATH') || exit;

/**
 * Builds the llms.txt content.
 *
 * We keep it simple:
 * - Auto mode: generates a small curated list of key pages + sitemap link
 * - Manual mode: prints the user-edited markdown
 */
final class LlmsTxtService
{
    private Container $container;
    private Settings $settings;

    public function __construct(Container $container)
    {
        $this->container = $container;
        $this->settings = $container->get('settings');
    }

    public function build(): string
    {
        $siteName = (string) get_bloginfo('name');
        if ($siteName === '') {
            $siteName = 'Website';
        }

        $summary = (string) get_bloginfo('description');
        $summary = trim(preg_replace('/\s+/', ' ', $summary));

        $llms = $this->settings->get('ai_readiness.llms', []);
        if (!is_array($llms)) {
            $llms = [];
        }

        $mode = isset($llms['mode']) ? sanitize_key((string) $llms['mode']) : 'auto';
        if (!in_array($mode, ['auto', 'manual'], true)) {
            $mode = 'auto';
        }

        $manual = isset($llms['manual']) ? (string) $llms['manual'] : '';
        $manual = trim((string) $manual);

        if ($mode === 'manual' && $manual !== '') {
            // If the user didn't include a H1, prepend a safe header.
            if (strpos(ltrim($manual), '#') !== 0) {
                $txt = "# {$siteName}\n\n";
                if ($summary !== '') {
                    $txt .= '> ' . $summary . "\n\n";
                }
                $txt .= $manual . "\n";
                return $this->normalizeLineEndings($txt);
            }

            return $this->normalizeLineEndings($manual . "\n");
        }

        // Auto mode.
        $auto = isset($llms['auto']) && is_array($llms['auto']) ? $llms['auto'] : [];
        $includePages = !empty($auto['include_pages']);
        $includePosts = !empty($auto['include_posts']);
        $maxLinks = isset($auto['max_links']) ? (int) $auto['max_links'] : 20;
        if ($maxLinks < 5) {
            $maxLinks = 5;
        }
        if ($maxLinks > 200) {
            $maxLinks = 200;
        }

        $lines = [];
        $lines[] = '# ' . $siteName;
        $lines[] = '';
        if ($summary !== '') {
            $lines[] = '> ' . $summary;
            $lines[] = '';
        }
        $lines[] = __('This file provides a curated list of important pages and discovery URLs for LLMs and AI assistants.', 'wp-seo-next');
        $brand = Branding::brand($this->settings);
        if ($brand !== '') {
            // translators: %s is brand name
            $lines[] = sprintf(__('Generated by %s (AI Search Readiness).', 'wp-seo-next'), $brand);
        } else {
            $lines[] = __('Generated by AI Search Readiness.', 'wp-seo-next');
        }
        $lines[] = '';

        // Key pages
        $links = $this->collectLinks($includePages, $includePosts, $maxLinks);

        $lines[] = '## ' . __('Key pages', 'wp-seo-next');
        foreach ($links as $link) {
            $url = $link['url'];
            $title = $link['title'];
            $desc = $link['desc'];

            if ($desc !== '') {
                $lines[] = '- [' . $title . '](' . $url . '): ' . $desc;
            } else {
                $lines[] = '- [' . $title . '](' . $url . ')';
            }
        }
        if (empty($links)) {
            $lines[] = '- ' . home_url('/');
        }
        $lines[] = '';

        // Discovery URLs
        $lines[] = '## ' . __('Discovery', 'wp-seo-next');
        $lines[] = '- [' . __('XML Sitemap index', 'wp-seo-next') . '](' . home_url('/sitemap_index.xml') . '): ' . __('All indexable URLs (recommended).', 'wp-seo-next');
        $lines[] = '- [' . __('Robots.txt', 'wp-seo-next') . '](' . home_url('/robots.txt') . '): ' . __('Crawl rules and policies.', 'wp-seo-next');
        $lines[] = '- [' . __('RSS feed', 'wp-seo-next') . '](' . get_feed_link('rss2') . '): ' . __('Latest content updates.', 'wp-seo-next');
        $lines[] = '';

        $txt = implode("\n", $lines) . "\n";
        return $this->normalizeLineEndings($txt);
    }

    /**
     * @return array<int,array{title:string,url:string,desc:string}>
     */
    private function collectLinks(bool $includePages, bool $includePosts, int $maxLinks): array
    {
        $items = [];

        // Always include home.
        $items[] = [
            'title' => (string) __('Homepage', 'wp-seo-next'),
            'url' => (string) home_url('/'),
            'desc' => '',
        ];

        $remaining = max(0, $maxLinks - 1);

        $pageLimit = 0;
        $postLimit = 0;

        if ($includePages && $includePosts) {
            $pageLimit = (int) ceil($remaining * 0.5);
            $postLimit = $remaining - $pageLimit;
        } elseif ($includePages) {
            $pageLimit = $remaining;
        } elseif ($includePosts) {
            $postLimit = $remaining;
        }

        if ($pageLimit > 0) {
            $pages = get_posts([
                'post_type' => 'page',
                'post_status' => 'publish',
                'orderby' => ['menu_order' => 'ASC', 'title' => 'ASC'],
                'posts_per_page' => $pageLimit,
                'no_found_rows' => true,
                'suppress_filters' => false,
            ]);

            if (is_array($pages)) {
                foreach ($pages as $p) {
                    if (!($p instanceof \WP_Post)) {
                        continue;
                    }
                    $url = get_permalink($p);
                    if (!$url) {
                        continue;
                    }
                    $items[] = [
                        'title' => $this->safeTitle($p->post_title, $p->ID),
                        'url' => $url,
                        'desc' => $this->safeDescription($p),
                    ];
                }
            }
        }

        if ($postLimit > 0) {
            $posts = get_posts([
                'post_type' => 'post',
                'post_status' => 'publish',
                'orderby' => ['date' => 'DESC'],
                'posts_per_page' => $postLimit,
                'no_found_rows' => true,
                'suppress_filters' => false,
            ]);

            if (is_array($posts)) {
                foreach ($posts as $p) {
                    if (!($p instanceof \WP_Post)) {
                        continue;
                    }
                    $url = get_permalink($p);
                    if (!$url) {
                        continue;
                    }
                    $items[] = [
                        'title' => $this->safeTitle($p->post_title, $p->ID),
                        'url' => $url,
                        'desc' => $this->safeDescription($p),
                    ];
                }
            }
        }

        // De-duplicate by URL.
        $seen = [];
        $out = [];
        foreach ($items as $it) {
            $url = isset($it['url']) ? (string) $it['url'] : '';
            if ($url === '' || isset($seen[$url])) {
                continue;
            }
            $seen[$url] = true;
            $out[] = $it;
            if (count($out) >= $maxLinks) {
                break;
            }
        }

        return $out;
    }

    private function safeTitle(string $title, int $id): string
    {
        $t = trim(wp_strip_all_tags($title));
        if ($t === '') {
            $t = '#' . (string) $id;
        }
        return $t;
    }

    private function safeDescription(\WP_Post $post): string
    {
        $text = '';

        $excerpt = (string) $post->post_excerpt;
        $excerpt = trim(wp_strip_all_tags($excerpt));
        if ($excerpt !== '') {
            $text = $excerpt;
        } else {
            $content = (string) $post->post_content;
            $content = wp_strip_all_tags($content);
            $content = trim(preg_replace('/\s+/', ' ', $content));
            if ($content !== '') {
                $text = $content;
            }
        }

        if ($text === '') {
            return '';
        }

        // Trim to ~140 chars (LLM friendly, similar to snippet).
        $max = 140;
        if (function_exists('mb_strlen') && function_exists('mb_substr')) {
            if (mb_strlen($text) > $max) {
                $text = (string) mb_substr($text, 0, $max);
                $text = rtrim($text, " \t\n\r\0\x0B\-–—,:;");
                $text .= '…';
            }
        } elseif (strlen($text) > $max) {
            $text = substr($text, 0, $max);
            $text = rtrim($text, " \t\n\r\0\x0B\-–—,:;");
            $text .= '…';
        }

        return $text;
    }

    private function normalizeLineEndings(string $txt): string
    {
        $txt = str_replace(["\r\n", "\r"], "\n", $txt);
        // Never return empty.
        if (trim($txt) === '') {
            return "# " . (string) get_bloginfo('name') . "\n";
        }
        return $txt;
    }
}
