<?php

namespace App\Services;

use App\Models\Site;
use App\Models\Topic;
use App\Models\Article;
use App\Helpers\Logger;

class PublisherService
{
    private TopicBalancer $topicBalancer;
    private OpenAIService $openAI;
    private InternalLinkService $internalLinkService;
    private ImageService $imageService;
    private WordPressService $wordpress;

    public function __construct()
    {
        $this->topicBalancer = new TopicBalancer();
        $this->openAI = new OpenAIService();
        $this->internalLinkService = new InternalLinkService();
        $this->imageService = new ImageService();
        $this->wordpress = new WordPressService();
    }

    public function publishNext(): array
    {
        Logger::info('Rozpoczynam automatyczna publikacje', 'publish');

        $sites = Site::findDueForPublishing();

        if (empty($sites)) {
            Logger::info('Brak stron do publikacji', 'publish');
            return ['success' => false, 'message' => 'Brak stron wymagajacych publikacji.'];
        }

        $site = $sites[0];
        return $this->publishForSite($site);
    }

    public function publishForSite(array $site): array
    {
        Logger::info("Publikacja dla strony: {$site['name']} (ID: {$site['id']})", 'publish');

        // 0. Najpierw uzupelnij obrazki w juz opublikowanych artykulach bez miniatury.
        $publishedWithoutImage = Article::findNextPublishedWithoutImageBySite((int) $site['id']);
        if ($publishedWithoutImage) {
            return $this->attachMissingImageToPublishedArticle($site, $publishedWithoutImage);
        }

        // 1. Najpierw publikuj gotowe, nieopublikowane artykuly.
        $retryArticle = Article::findNextRetryableBySite((int) $site['id']);
        if ($retryArticle) {
            $topic = Topic::find((int) $retryArticle['topic_id']);
            if (!$topic) {
                Logger::error("Nie znaleziono tematu dla artykulu ID {$retryArticle['id']}", 'publish');
                return ['success' => false, 'message' => 'Nie znaleziono tematu dla oczekujacego artykulu.'];
            }

            Logger::info("Ponowna proba publikacji artykulu ID {$retryArticle['id']}: {$retryArticle['title']}", 'publish');
            Article::markRetryAttempt((int) $retryArticle['id']);

            return $this->publishPreparedArticle(
                $site,
                $topic,
                [
                    'title' => (string) $retryArticle['title'],
                    'content' => (string) $retryArticle['content'],
                    'model' => $retryArticle['ai_model'] ?? null,
                    'prompt' => $retryArticle['prompt_used'] ?? null,
                ],
                (int) $retryArticle['id']
            );
        }

        // 2. Gdy brak zaleglych, generuj nowy artykul.
        $topic = $this->topicBalancer->getNextTopic($site['id']);
        if (!$topic) {
            Logger::error("Brak aktywnych tematow dla strony {$site['name']}", 'publish');
            return ['success' => false, 'message' => "Brak aktywnych tematow dla strony {$site['name']}."];
        }

        Logger::info("Wybrany temat: {$topic['name']} (ID: {$topic['id']})", 'publish');

        $existingTitles = Article::getRecentTitlesByTopic((int) $topic['id'], 20);

        $article = $this->openAI->generateArticle(
            $topic['name'],
            $topic['description'] ?? '',
            $existingTitles
        );

        if (!$article) {
            $this->saveFailedArticle($site, $topic, 'Nie udalo sie wygenerowac artykulu przez OpenAI.');
            return ['success' => false, 'message' => 'Blad generowania artykulu przez AI.'];
        }

        Logger::info("Wygenerowano artykul: {$article['title']}", 'publish');

        $article['title'] = $this->normalizeArticleTitle((string) ($article['title'] ?? ''), (string) $topic['name']);

        return $this->publishPreparedArticle($site, $topic, $article);
    }

    private function publishPreparedArticle(array $site, array $topic, array $article, ?int $existingArticleId = null): array
    {
        $linkingResult = $this->internalLinkService->enrichContentWithInternalLinks(
            $site,
            (string) ($article['title'] ?? ''),
            (string) ($article['content'] ?? '')
        );
        $article['content'] = (string) ($linkingResult['content'] ?? (string) ($article['content'] ?? ''));
        Logger::info(
            'Internal linking mode=' . (string) ($linkingResult['mode'] ?? 'unknown')
                . ', links_added=' . (int) ($linkingResult['links_added'] ?? 0),
            'publish'
        );

        $imageUrl = null;
        $mediaId = null;
        $image = $this->imageService->generate((string) $article['title'], (string) $topic['name']);

        if ($image) {
            $mediaId = $this->wordpress->uploadMedia($site, $image['data'], $image['filename']);
            if ($mediaId) {
                $imageUrl = 'wp_media:' . $mediaId;
                Logger::info("Upload obrazka: media_id={$mediaId}", 'publish');
            }
        } else {
            Logger::warning('Nie udalo sie wygenerowac obrazka, publikacja bez obrazka', 'publish');
        }

        $wpPostId = $this->wordpress->createPost(
            $site,
            (string) $article['title'],
            (string) $article['content'],
            $topic['wp_category_id'],
            $mediaId,
            $this->buildExcerpt((string) $article['content'])
        );

        if (!$wpPostId) {
            $this->saveFailedArticle(
                $site,
                $topic,
                'Nie udalo sie opublikowac posta na WordPress.',
                $article,
                $existingArticleId
            );
            return ['success' => false, 'message' => 'Blad publikacji na WordPress.'];
        }

        Logger::info("Opublikowano post: wp_post_id={$wpPostId}", 'publish');
        $wpPostUrl = $this->wordpress->getPostLink($site, (int) $wpPostId);

        if ($existingArticleId !== null) {
            Article::update($existingArticleId, [
                'title' => (string) $article['title'],
                'content' => (string) $article['content'],
                'wp_post_id' => $wpPostId,
                'wp_post_url' => $wpPostUrl,
                'image_url' => $imageUrl,
                'status' => 'published',
                'ai_model' => $article['model'] ?? null,
                'prompt_used' => $article['prompt'] ?? null,
                'error_message' => null,
                'published_at' => date('Y-m-d H:i:s'),
            ]);
        } else {
            Article::create([
                'site_id' => $site['id'],
                'topic_id' => $topic['id'],
                'title' => (string) $article['title'],
                'content' => (string) $article['content'],
                'wp_post_id' => $wpPostId,
                'wp_post_url' => $wpPostUrl,
                'image_url' => $imageUrl,
                'status' => 'published',
                'ai_model' => $article['model'] ?? null,
                'prompt_used' => $article['prompt'] ?? null,
                'published_at' => date('Y-m-d H:i:s'),
            ]);
        }

        Topic::incrementArticleCount((int) $topic['id']);
        Site::updateLastPublished((int) $site['id']);

        $message = "Opublikowano: \"{$article['title']}\" na {$site['name']}";
        Logger::info($message, 'publish');

        return ['success' => true, 'message' => $message];
    }

    private function normalizeArticleTitle(string $title, string $topicName): string
    {
        $title = trim($title);
        $topicName = trim($topicName);

        if ($title === '' || $topicName === '') {
            return $title;
        }

        // Remove "<topic name>: " / "<topic name> - " prefixes from generated titles.
        $topicPattern = preg_quote($topicName, '/');
        $normalized = preg_replace('/^' . $topicPattern . '\s*[:\-\x{2013}\x{2014}|]\s*/iu', '', $title);
        $normalized = is_string($normalized) ? trim($normalized) : $title;

        return $normalized !== '' ? $normalized : $title;
    }

    private function saveFailedArticle(
        array $site,
        array $topic,
        string $error,
        ?array $article = null,
        ?int $existingArticleId = null
    ): void {
        if ($existingArticleId !== null) {
            Article::update($existingArticleId, [
                'title' => $article['title'] ?? 'FAILED - nie wygenerowano',
                'content' => $article['content'] ?? '',
                'status' => 'failed',
                'ai_model' => $article['model'] ?? null,
                'prompt_used' => $article['prompt'] ?? null,
                'error_message' => $error,
            ]);
        } else {
            Article::create([
                'site_id' => $site['id'],
                'topic_id' => $topic['id'],
                'title' => $article['title'] ?? 'FAILED - nie wygenerowano',
                'content' => $article['content'] ?? '',
                'status' => 'failed',
                'ai_model' => $article['model'] ?? null,
                'prompt_used' => $article['prompt'] ?? null,
                'error_message' => $error,
            ]);
        }

        Logger::error("Publikacja nieudana: {$error}", 'publish');
    }

    private function attachMissingImageToPublishedArticle(array $site, array $article): array
    {
        $articleId = (int) $article['id'];
        $wpPostId = (int) ($article['wp_post_id'] ?? 0);

        if ($wpPostId <= 0) {
            Logger::warning("Artykul ID {$articleId} oznaczony jako published bez wp_post_id - pomijam", 'publish');
            return ['success' => false, 'message' => 'Brak wp_post_id dla opublikowanego artykulu.'];
        }

        $existingFeaturedMediaId = $this->wordpress->getPostFeaturedMedia($site, $wpPostId);
        if ($existingFeaturedMediaId !== null) {
            Article::update($articleId, ['image_url' => 'wp_media:' . $existingFeaturedMediaId]);
            $message = "Artykul ID {$articleId} juz mial miniaturke (media_id={$existingFeaturedMediaId}) - zaktualizowano marker lokalny.";
            Logger::info($message, 'publish');
            return ['success' => true, 'message' => $message];
        }

        $topic = Topic::find((int) ($article['topic_id'] ?? 0));
        $topicName = $topic['name'] ?? (string) $article['title'];
        $title = (string) ($article['title'] ?? 'Artykul bez tytulu');

        Article::markRetryAttempt($articleId);

        Logger::info("Proba uzupelnienia obrazka dla artykulu ID {$articleId}: {$title}", 'publish');

        $image = $this->imageService->generate($title, (string) $topicName);
        if (!$image) {
            $message = "Nie udalo sie wygenerowac obrazka dla opublikowanego artykulu ID {$articleId}.";
            Logger::warning($message, 'publish');
            return ['success' => false, 'message' => $message];
        }

        $mediaId = $this->wordpress->uploadMedia($site, $image['data'], $image['filename']);
        if (!$mediaId) {
            $message = "Nie udalo sie wyslac obrazka do WordPress dla artykulu ID {$articleId}.";
            Logger::warning($message, 'publish');
            return ['success' => false, 'message' => $message];
        }

        $updated = $this->wordpress->updatePostFeaturedMedia($site, $wpPostId, $mediaId);
        if (!$updated) {
            $this->wordpress->deleteMedia($site, $mediaId);
            $message = "Nie udalo sie podpiac miniaturki (media_id={$mediaId}) do wpisu wp_post_id={$wpPostId}.";
            Logger::warning($message, 'publish');
            return ['success' => false, 'message' => $message];
        }

        Article::update($articleId, [
            'image_url' => 'wp_media:' . $mediaId,
            'error_message' => null,
        ]);

        $message = "Uzupelniono miniaturke dla artykulu ID {$articleId} (wp_post_id={$wpPostId}, media_id={$mediaId}).";
        Logger::info($message, 'publish');

        return ['success' => true, 'message' => $message];
    }

    private function buildExcerpt(string $htmlContent): string
    {
        $plain = trim((string) preg_replace('/\s+/u', ' ', strip_tags($htmlContent)));
        if ($plain === '') {
            return '';
        }

        $maxLength = 155;
        if (mb_strlen($plain) <= $maxLength) {
            return $plain;
        }

        $cut = mb_substr($plain, 0, $maxLength + 1);
        $lastSpace = mb_strrpos($cut, ' ');
        if ($lastSpace !== false && $lastSpace > 80) {
            $cut = mb_substr($cut, 0, $lastSpace);
        } else {
            $cut = mb_substr($cut, 0, $maxLength);
        }

        return rtrim($cut, " \t\n\r\0\x0B.,;:!?") . '.';
    }
}
