<?php

namespace App\Services;

use App\Models\GameAccountUser;
use App\Models\LoginScreenNews;
use Illuminate\Support\Collection;
use Illuminate\Support\Str;

class LoginScreenNewsService
{
    public const FEED_HEADER = 'SERVERALERT:';

    public const SECTION_SEPARATOR = '----------------------------------------------------------';

    public const EMPTY_MESSAGE = '|cFFB7C1CFСкоро здесь появятся новости сервера.|r';

    /**
     * @return \Illuminate\Support\Collection<int, \App\Models\LoginScreenNews>
     */
    public function listForAdmin(): Collection
    {
        return LoginScreenNews::query()
            ->ordered()
            ->get();
    }

    /**
     * @return array{total: int, published: int, draft: int}
     */
    public function stats(): array
    {
        $total = LoginScreenNews::query()->count();
        $published = LoginScreenNews::query()->published()->count();

        return [
            'total' => $total,
            'published' => $published,
            'draft' => $total - $published,
        ];
    }

    /**
     * @param  array{title: string, body: string, sort_order: int, is_published?: bool}  $attributes
     */
    public function create(array $attributes, ?GameAccountUser $actor): LoginScreenNews
    {
        return LoginScreenNews::query()->create([
            ...$this->normalizeAttributes($attributes),
            'created_by_account_id' => $actor?->id,
            'created_by_username' => $actor?->username,
            'updated_by_account_id' => $actor?->id,
            'updated_by_username' => $actor?->username,
        ]);
    }

    /**
     * @param  array{title: string, body: string, sort_order: int, is_published?: bool}  $attributes
     */
    public function update(LoginScreenNews $newsItem, array $attributes, ?GameAccountUser $actor): LoginScreenNews
    {
        $newsItem->forceFill([
            ...$this->normalizeAttributes($attributes),
            'updated_by_account_id' => $actor?->id,
            'updated_by_username' => $actor?->username,
        ])->save();

        return $newsItem->refresh();
    }

    public function delete(LoginScreenNews $newsItem): void
    {
        $newsItem->delete();
    }

    public function renderFeed(): string
    {
        $sections = LoginScreenNews::query()
            ->published()
            ->ordered()
            ->pluck('body')
            ->map(fn (mixed $body): string => $this->normalizeBody((string) $body))
            ->filter(fn (string $body): bool => $body !== '')
            ->values();

        $payload = $sections->isNotEmpty()
            ? $sections->implode("\n".self::SECTION_SEPARATOR."\n")
            : self::EMPTY_MESSAGE;

        return self::FEED_HEADER."\n\n".$payload."\n";
    }

    /**
     * @param  array{title: string, body: string, sort_order: int, is_published?: bool}  $attributes
     * @return array{title: string, body: string, sort_order: int, is_published: bool}
     */
    private function normalizeAttributes(array $attributes): array
    {
        return [
            'title' => trim($attributes['title']),
            'body' => $this->normalizeBody($attributes['body']),
            'sort_order' => (int) $attributes['sort_order'],
            'is_published' => (bool) ($attributes['is_published'] ?? false),
        ];
    }

    private function normalizeBody(string $body): string
    {
        $normalized = trim(str_replace(["\r\n", "\r"], "\n", $body));

        if (Str::startsWith($normalized, self::FEED_HEADER)) {
            $normalized = trim(Str::after($normalized, self::FEED_HEADER));
        }

        return $normalized;
    }
}
