<?php
require_once 'ArticleManagerDAO.php';
require_once 'Article.php';
/**
 * Klasse: Eine lokale Lösung des ArticleManagerDAO.
 * Schreibt zunächst Daten lokal in das Verzeichnis und kann diese wieder auslesen.
 *
 * @author Niklas Ortmann
 */
class LocalArticleManager implements ArticleManagerDAO {

    private $file;
    private static $instance = null;

    /**
     * Konstruktor
     */
    public function __construct()
    {
        $this->file = __DIR__ . '/../../data/articles.json';
    }

    /**
     * Gibt die LocalArticleManager-Instanz zurück.
     * @return LocalArticleManager
     */
    public static function getInstance()
    {
        if (self::$instance == null) {
            self::$instance = new LocalArticleManager();
        }
        return self::$instance;
    }

    /**
     * Speichert alle Artikel/Beiträge in der Datei.
     * @param $articles
     * @return void
     * @throws InternalServerErrorException
     */
    private function saveArticle($articles)
    {
        try{
            file_put_contents(
                $this->file,
                json_encode($articles, JSON_PRETTY_PRINT)
            );
        }catch (Exception $e){
            throw new InternalServerErrorException($e->getMessage());
        }

    }

    public function addArticle($title, $content, $author, $category, $tags)
    {
        $articles = $this->getAllArticles();

        $articles[] = [
            "id" => count($articles)+1,
            "title" => $title,
            "content" => $content,
            "author" => $author,
            "category" => $category,
            "tags" => $tags,
            "creationDate" => date("Y-m-d H:i:s"),
            "likes" => []
        ];

        $this->saveArticle($articles);
    }

    public function updateArticle($id, $article, $author)
    {
        if (empty($article)) {
            throw new NotFoundException("not_found_article");
        }

        // Berechtigungsprüfung:
        if ($article->getAuthor() !== $author) {
            throw new UnauthorizedAccessException("unauthorized_access");
        }

        // Beitrag aktualisieren:
        $articles = $this->getAllArticles();
        $updated = false;

        foreach ($articles as $index => $storedArticle) {
            if (isset($storedArticle['id']) && $storedArticle['id'] == $id) {
                $articles[$index] = [
                    "id" => $id,
                    "title" => $article->getTitle(),
                    "content" => $article->getContent(),
                    "author" => $author,
                    "category" => $article->getCategory(),
                    "tags" => $article->getTags(),
                    "creationDate" => $article->getCreationDate(),
                    "likes" => $storedArticle['likes'] ?? []
                ];
                $updated = true;
                break;
            }
        }

        // Nur speichern, wenn Beitrag geändert wurde:
        if ($updated) {
            $this->saveArticle($articles);
        } else {
            throw new NotFoundException("missing_id");
        }
    }

    public function deleteArticle($id, $author)
    {
        $article = getArticle($id);
        if (empty($article)) {
            throw new NotFoundException("not_found_article");
        }

        // Berechtigungsprüfung:
        if ($article->getAuthor() !== $author) {
            throw new UnauthorizedAccessException("unauthorized_access");
        }

        $articles = $this->getAllArticles();
        $articleFound = false;

        foreach ($articles as $index => $article) {
            if (isset($article['id']) && $article['id'] == $id) {
                unset($articles[$index]);
                $articleFound = true;
                break; // Schleife abbrechen, da die ID eindeutig ist
            }
        }

        if ($articleFound) {
            // array_values stellt sicher, dass die Array-Keys wieder fortlaufend bei 0 beginnen
            $this->saveArticle(array_values($articles));
        }
    }

    public function getArticle($id)
    {
        $articles = $this->getAllArticles();

        foreach ($articles as $article) {
            if (isset($article['id']) && $article['id'] == $id) {
                $likes = isset($article['likes']) && is_array($article['likes']) ? $article['likes'] : [];
                return new Article(
                    intval($article['id']),
                    $article['title'],
                    $article['content'],
                    $article['author'],
                    $article['category'],
                    $article['tags'],
                    $article['creationDate'],
                    $likes
                    );
            }
        }

        return null;
    }

    public function getAllArticles(): array
    {
        if (!file_exists($this->file)) {
            return [];
        }

        $json = file_get_contents($this->file);
        $articles = json_decode($json, true);

        return is_array($articles) ? $articles : [];
    }

    public function getArticlesByAuthor($author)
    {
        $articles = $this->getAllArticles();
        $filteredArticles = [];

        foreach ($articles as $article) {
            if (isset($article['author']) && $article['author'] == $author) {
                $likes = isset($article['likes']) && is_array($article['likes']) ? $article['likes'] : [];
                $filteredArticles[] = new Article(
                    intval($article['id']),
                    $article['title'],
                    $article['content'],
                    $article['author'],
                    $article['category'],
                    $article['tags'],
                    $article['creationDate'],
                    $likes
                );
            }
        }
        return $filteredArticles;
    }


    public function search(string $keyword): array
    {
        $articles = $this->getAllArticles();
        $filteredArticles = [];

        if (!is_array($articles)) {
            return [];
        }

        $cleanKeyword = strtolower(trim($keyword));

        foreach ($articles as $article) {
            $title = isset($article['title']) ? strtolower((string)$article['title']) : '';
            $content = isset($article['content']) ? strtolower((string)$article['content']) : '';
            $tags = isset($article['tags']) ? strtolower((string)$article['tags']) : '';

            if (($cleanKeyword !== '' && strpos($title, $cleanKeyword) !== false) ||
                ($cleanKeyword !== '' && strpos($content, $cleanKeyword) !== false) ||
                ($cleanKeyword !== '' && strpos($tags, $cleanKeyword) !== false)) {

                $likes = isset($article['likes']) && is_array($article['likes']) ? $article['likes'] : [];
                $filteredArticles[] = new Article(
                    intval($article['id'] ?? 0),
                    $article['title'] ?? '',
                    $article['content'] ?? '',
                    $article['author'] ?? '',
                    $article['category'] ?? '',
                    $article['tags'] ?? '',
                    $article['creationDate'] ?? '',
                    $likes
                );
            }
        }

        return $filteredArticles;
    }

    public function getArticlesByCategory($category)
    {
        $articles = $this->getAllArticles();
        $filteredArticles = [];

        foreach ($articles as $article) {
            if (isset($article['category']) && $article['category'] == $category) {
                $likes = isset($article['likes']) && is_array($article['likes']) ? $article['likes'] : [];
                $filteredArticles[] = new Article(
                    intval($article['id']),
                    $article['title'],
                    $article['content'],
                    $article['author'],
                    $article['category'],
                    $article['tags'],
                    $article['creationDate'],
                    $likes
                );
            }
        }
        return $filteredArticles;
    }

    public function toggleLike(int $articleId, string $userId): bool
    {
        $articles = $this->getAllArticles();
        $articleFound = false;
        $isLikedNow = false;

        foreach ($articles as $index => $article) {
            if (isset($article['id']) && $article['id'] == $articleId) {
                $articleFound = true;

                // Likes-Array initialisieren, falls nicht vorhanden
                if (!isset($articles[$index]['likes']) || !is_array($articles[$index]['likes'])) {
                    $articles[$index]['likes'] = [];
                }

                $likeIndex = array_search($userId, $articles[$index]['likes']);

                if ($likeIndex !== false) {
                    // Bereits geliked -> Unlike
                    unset($articles[$index]['likes'][$likeIndex]);
                    // Array-Keys neu indizieren, damit JSON sauber bleibt
                    $articles[$index]['likes'] = array_values($articles[$index]['likes']);
                    $isLikedNow = false;
                } else {
                    // Noch nicht geliked -> Like (User-ID hinzufügen)
                    $articles[$index]['likes'][] = $userId;
                    $isLikedNow = true;
                }
                break;
            }
        }

        if (!$articleFound) {
            throw new NotFoundException("missing_id");
        }

        $this->saveArticle($articles);
        return $isLikedNow;
    }

}
?>