<?php

namespace Blog\Model;

use DateTime;
use PDO;
use PDOException;

class AuthModel extends Database
{
    public function login(string $email, string $password)
    {
        $pdo = $this->linkDB();
        $sql = "SELECT email, password, valid_until, is_admin FROM user WHERE email = :email";
        $params = [":email" => $email];

        try {
            $sth = $pdo->prepare($sql);
            $sth->execute($params);
            $user = $sth->fetch(PDO::FETCH_ASSOC);
        } catch (PDOException $e) {
            new \Blog\Library\ErrorMsg("Fehler beim Abrufen der Benutzerdaten.", $e);
            return ['success' => false, 'error' => "Interner Datenbankfehler."];
        }

        if (!$user) {
            return ['success' => false, 'error' => "Benutzer mit dieser E-Mail wurde nicht gefunden."];
        }

        if (!password_verify($password, $user['password'])) {
            return ['success' => false, 'error' => "Das eingegebene Passwort ist falsch."];
        }

        try {
            $now = new DateTime();
            $validUntil = new DateTime($user['valid_until']);

            if ($now > $validUntil) {
                return ['success' => false, 'error' => "Ihr Passwort ist abgelaufen. Bitte setzen Sie ein neues über \"Passwort vergessen\"."];
            }
        } catch (\Exception $e) {
            new \Blog\Library\ErrorMsg("Fehler beim Verarbeiten des Gültigkeitsdatums.", $e);
            return ['success' => false, 'error' => "Fehler bei der Passwortprüfung."];
        }

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

    public function register($data) {
        if (!filter_var($data['email'], FILTER_VALIDATE_EMAIL)) {
            return "Bitte geben Sie eine gültige E-Mail ein.";
        }

        $requiredFields = [
            'email', 'password', 'password_repeat', 'street', 'house_number', 'city', 'postal_code',
            'country', 'first_name', 'last_name', 'phone'
        ];

        foreach ($requiredFields as $field) {
            if (empty($data[$field])) {
                return "Bitte füllen Sie alle Felder aus.";
            }
        }

        if ($this->userExistsByEmail($data['email'])) {
            return "Ein Account mit dieser E-Mail existiert bereits.";
        }

        // Passwort-Validierung
        if (!$this->checkDoublePw($data['password'], $data['password_repeat'])) {
            return "Passwörter stimmen nicht überein.";
        }

        $pwCheck = $this->pwRequirementCheck($data['password']);
        if ($pwCheck !== true) {
            return $pwCheck; // Array mit spezifischen Fehlern zurückgeben
        }

        $hashedPassword = password_hash($data['password'], PASSWORD_DEFAULT);

        $sql = "INSERT INTO user (email, password, street, house_number, city, postal_code, country, first_name, last_name, phone, is_admin) 
                VALUES (:email, :password, :street, :house_number, :city, :postal_code, :country, :first_name, :last_name, :phone, :is_admin)";

        $params = [
            ':email' => $data['email'],
            ':password' => $hashedPassword,
            ':street' => $data['street'],
            ':house_number' => $data['house_number'],
            ':city' => $data['city'],
            ':postal_code'=> $data['postal_code'],
            ':country'=> $data['country'],
            ':first_name' => $data['first_name'],
            ':last_name'=> $data['last_name'],
            ':phone' => $data['phone'],
            ':is_admin' => $data['is_admin'] ? 1 : 0,
        ];

        try {
            $pdo = $this->linkDB();
            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);
            return true;
        } catch (PDOException $e) {
            new \Blog\Library\ErrorMsg("Fehler beim Schreiben der Daten.", $e);
            return false;
        }
    }

    private function userExistsByEmail($email) {
        try {
            $pdo = $this->linkDB();

            $sql = "SELECT user_id FROM user WHERE email = :email";
            $params = [':email' => $email];

            $stmt = $pdo->prepare($sql);
            $stmt->execute($params);

            return (bool) $stmt->fetch();
        } catch (\PDOException $e) {
            new \Blog\Library\ErrorMsg("Fehler bei der E-Mail-Prüfung", $e);
            return false;
        }
    }

    public function pwForgot($email){
        $randomPw = bin2hex(random_bytes(12 / 2));
        $hashedPassword = password_hash($randomPw, PASSWORD_DEFAULT);

        $this->forgottenPwUpdate($email, $hashedPassword);

        $betreff = "Passwort zurücksetzen bei bibArts";
        $nachricht = "Hallo,\n\nhier ihr temporäres Passwort:\n\n $randomPw \n\n Bitte beachten Sie, dass das Passwort nur 2 stunden Gülltig ist. \nViele Grüße,\nbibArts Team";

        $header = "From: noreply@edu.bib.de\r\n";
        $header .= "Content-Type: text/plain; charset=UTF-8\r\n";

        $maxTries = 5;
        $try = 0;
        $success = false;

        while ($try < $maxTries && !$success) {
            $erfolg = mail($email, $betreff, $nachricht, $header);
            $try++;
            if (!$erfolg) {
                error_log("Mailversuch $try an $email fehlgeschlagen.");
                sleep(1);
            }
        }
    }

    private function forgottenPwUpdate($email, $hashedPassword) {
        try{
            $pdo = $this->linkDB();

            $sqlCheck = "SELECT COUNT(*) FROM user WHERE email = :email";
            $stmt = $pdo->prepare($sqlCheck);
            $stmt->execute([':email' => $email]);
            if ($stmt->fetchColumn() == 0) {
                return false;
            }

            $validUntil = (new DateTime())->add(new DateInterval('PT2H'))->format('Y-m-d H:i:s');


            $sql = "UPDATE user 
                    SET password = :password, valid_until = :valid_until
                    WHERE email = :email";

            $stmt = $pdo->prepare($sql);
            $params = [
                ':email' => $email,
                ':password' => $hashedPassword,
                ':valid_until' => $validUntil
            ];
            return $stmt->execute($params);
        } catch (PDOException $e) {
            new \Blog\Library\ErrorMsg("Fehler beim Aktualisieren der Daten.", $e);
            die;
            return false;
        }
    }

    public function updatePassword($email, $oldpw, $newpw){
        if(!$this->login($email, $oldpw)) {
            return false;
        }

        $requiredFields = [$email, $oldpw, $newpw];
        foreach ($requiredFields as $field) {
            if (empty($field)) {
                return "Bitte füllen Sie alle Felder aus";
            }
        }
        $hashedPassword = password_hash($newpw, PASSWORD_DEFAULT);

        $sql = "UPDATE user SET password = :password WHERE email = :email";

        try{
            $pdo = $this->linkDB();
            $stmt = $pdo->prepare($sql);
            $params = [
                ':email' => $email,
                ':password' => $hashedPassword,
            ];
            return $stmt->execute($params);
        } catch (PDOException $e) {
            new \Blog\Library\ErrorMsg("Fehler beim Schreiben der Daten.", $e);
            die;
        }
    }

    public function checkDoublePw($password1, $password2){
        if($password1 === $password2){
            return true;
        }
        else
            return false;
    }

    public function pwRequirementCheck($password){
        $error = [];

        if(strlen($password) < 8)
            $error[] = "Passwort: mindestens 8 Zeichen";
        if(!preg_match("/[A-Z]/", $password))
            $error[] = "Passwort: mindestens ein Großbuchstabe";
        if(!preg_match("/[a-z]/", $password))
            $error[] = "Passwort: mindestens ein Kleinbuchstabe";
        if(!preg_match("/[0-9]/", $password))
            $error[] = "Passwort: mindestens eine Zahl";
        if(!preg_match("/[^a-zA-Z0-9\s]/", $password))
            $error[] = "Passwort: mindestens ein Sonderzeichen";

        if(empty($error))
            return true;
        else
            return $error;
    }
}
