<?php

require_once "UserManagerDAO.php";

class LocalUserManager implements UserManagerDAO {

    private string $file = "data/users.json";

    public static function getInstance(){
        // TODO: implement the getIsntance method.
    }

    /**
     * Lädt alle Benutzer aus der JSON-Datei.
     *
     * @return array Liste aller Benutzer
     * @throws RuntimeException wenn die Datei nicht gelesen werden kann
     * oder fehlerhafte JSON-Daten enthält
     */
    private function loadUsers() {
        if (!file_exists($this->file)) {
            return [];
        }

        $json = file_get_contents($this->file);

        if ($json === false) {
            throw new RuntimeException("Benutzerdaten konnten nicht gelesen werden.");
        }

        $users = json_decode($json, true);

        if ($users === null && json_last_error() !== JSON_ERROR_NONE) {
            throw new RuntimeException("Benutzerdaten sind fehlerhaft.");
        }

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

    /**
     * Speichert alle Benutzer in die JSON-Datei.
     *
     * @param array $users Liste aller Benutzer
     * @return void
     * @throws RuntimeException wenn die Daten nicht gespeichert werden können
     */
    private function saveUsers($users) {
        $json = json_encode($users, JSON_PRETTY_PRINT);

        if ($json === false) {
            throw new RuntimeException("Benutzerdaten konnten nicht umgewandelt werden.");
        }

        $result = file_put_contents($this->file, $json);

        if ($result === false) {
            throw new RuntimeException("Benutzerdaten konnten nicht gespeichert werden.");
        }
    }

    /**
     * Sucht einen Benutzer anhand seiner E-Mail-Adresse.
     *
     * @param string $email E-Mail-Adresse des gesuchten Benutzers
     * @return array|null Benutzerdaten oder null, wenn kein Benutzer gefunden wurde
     * @throws RuntimeException wenn die Benutzerdaten nicht gelesen werden können
     */
    public function findUser($email) {
        $users = $this->loadUsers();

        foreach ($users as $user) {
            if (isset($user["email"]) && $user["email"] === $email) {

                if (!isset($user["vorname"]) && isset($user["username"])) {
                    $nameParts = explode(" ", $user["username"], 2);
                    $user["vorname"] = $nameParts[0] ?? "";
                    $user["nachname"] = $nameParts[1] ?? "";
                }

                return $user;
            }
        }

        return null;
    }

    /**
     * Fügt einen neuen Benutzer hinzu.
     *
     * @param string $email E-Mail-Adresse
     * @param string $vorname Vorname
     * @param string $nachname Nachname
     * @param string $password Passwort-Hash
     * @return void
     * @throws InvalidArgumentException wenn die E-Mail-Adresse bereits verwendet wird
     * @throws RuntimeException wenn die Benutzerdaten nicht gelesen oder gespeichert werden können
     */
    public function addUser($email, $vorname, $nachname, $password) {
        $users = $this->loadUsers();

        foreach ($users as $user) {
            if (isset($user["email"]) && $user["email"] === $email) {
                throw new InvalidArgumentException("Diese E-Mail-Adresse wird bereits verwendet.");
            }
        }

        $users[] = [
            "email" => $email,
            "vorname" => $vorname,
            "nachname" => $nachname,
            "password" => $password
        ];

        $this->saveUsers($users);
    }

    /**
     * Aktualisiert einen bestehenden Benutzer.
     *
     * @param string $oldEmail Alte E-Mail-Adresse
     * @param string $newEmail Neue E-Mail-Adresse
     * @param string $vorname Neuer Vorname
     * @param string $nachname Neuer Nachname
     * @param string|null $password Neues Passwort oder null
     * @return bool true, wenn der Benutzer aktualisiert wurde, sonst false
     * @throws InvalidArgumentException wenn die neue E-Mail-Adresse bereits verwendet wird
     * @throws RuntimeException wenn die Benutzerdaten nicht gelesen oder gespeichert werden können
     */
    public function updateUser($oldEmail, $newEmail, $vorname, $nachname, $password = null) {
        $users = $this->loadUsers();

        foreach ($users as $user) {
            if (
                isset($user["email"])
                && $user["email"] === $newEmail
                && $newEmail !== $oldEmail
            ) {
                throw new InvalidArgumentException("Diese E-Mail-Adresse wird bereits verwendet.");
            }
        }

        foreach ($users as $i => $user) {
            if (isset($user["email"]) && $user["email"] === $oldEmail) {
                $users[$i]["email"] = $newEmail;
                $users[$i]["vorname"] = $vorname;
                $users[$i]["nachname"] = $nachname;

                unset($users[$i]["username"]);

                if (!empty($password)) {
                    $users[$i]["password"] = password_hash($password, PASSWORD_DEFAULT);
                }

                $this->saveUsers($users);
                return true;
            }
        }

        return false;
    }

    /**
     * Löscht einen Benutzer anhand seiner E-Mail-Adresse.
     *
     * TODO: wenn ein Benutzer gelöscht wird, sollten dann auch seine Beiträge gelöscht werden?
     *
     * @param string $email E-Mail-Adresse des zu löschenden Benutzers
     * @return bool true, wenn der Benutzer gelöscht wurde, sonst false
     * @throws RuntimeException wenn die Benutzerdaten nicht gelesen oder gespeichert werden können
     */
    public function deleteUser($email) {
        $users = $this->loadUsers();

        foreach ($users as $i => $user) {
            if (isset($user["email"]) && $user["email"] === $email) {
                unset($users[$i]);
                $users = array_values($users);
                $this->saveUsers($users);
                return true;
            }
        }

        return false;
    }
}