<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
require_once $_SERVER['DOCUMENT_ROOT'] . '/includes/session_bootstrap.php';

$host = "localhost";
$db = "togethere_cloud";
$user = "root";
$pass = "HasloDoSQL";

try {
    $pdo = new PDO(
        "mysql:host=$host;dbname=$db;charset=utf8mb4",
        $user,
        $pass,
        [PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION]
    );
    $pdo->exec("SET NAMES utf8mb4 COLLATE utf8mb4_unicode_ci");
} catch (PDOException $e) {
    die("Błąd połączenia z bazą danych: " . $e->getMessage());
}

function tableExists(PDO $pdo, string $tableName): bool {
    try {
        $stmt = $pdo->prepare(
            'SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = :table'
        );
        $stmt->execute([':table' => $tableName]);
        return (int) $stmt->fetchColumn() > 0;
    } catch (Throwable $e) {
        return false;
    }
}

function getTableColumns(PDO $pdo, string $tableName): array {
    try {
        $stmt = $pdo->prepare(
            'SELECT COLUMN_NAME FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = :table'
        );
        $stmt->execute([':table' => $tableName]);
        $columns = $stmt->fetchAll(PDO::FETCH_COLUMN);
        return is_array($columns) ? $columns : [];
    } catch (Throwable $e) {
        return [];
    }
}

function getLoginUserByEmail(PDO $pdo, string $email): ?array {
    $userColumns = getTableColumns($pdo, 'users');
    if ($userColumns === []) {
        $stmt = $pdo->prepare('SELECT * FROM users WHERE email = ? LIMIT 1');
        $stmt->execute([$email]);
        $row = $stmt->fetch(PDO::FETCH_ASSOC);
        return is_array($row) ? $row : null;
    }

    $selectParts = [
        'id',
        'username',
        'email',
        'password',
    ];

    $optionalDefaults = [
        'email_verified' => '1 AS email_verified',
        'disabled' => '0 AS disabled',
        'role' => "'user' AS role",
    ];

    foreach ($optionalDefaults as $column => $fallbackSql) {
        $selectParts[] = in_array($column, $userColumns, true) ? $column : $fallbackSql;
    }

    $stmt = $pdo->prepare('SELECT ' . implode(', ', $selectParts) . ' FROM users WHERE email = ? LIMIT 1');
    $stmt->execute([$email]);
    $row = $stmt->fetch(PDO::FETCH_ASSOC);

    return is_array($row) ? $row : null;
}

function verifyAndUpgradePassword(PDO $pdo, array &$user, string $plainPassword): bool
{
    $storedPassword = isset($user['password']) ? (string) $user['password'] : '';
    if ($storedPassword === '') {
        return false;
    }

    if (password_verify($plainPassword, $storedPassword)) {
        if (password_needs_rehash($storedPassword, PASSWORD_DEFAULT)) {
            $newHash = password_hash($plainPassword, PASSWORD_DEFAULT);
            $stmt = $pdo->prepare('UPDATE users SET password = ? WHERE id = ?');
            $stmt->execute([$newHash, $user['id']]);
            $user['password'] = $newHash;
        }

        return true;
    }

    if (!hash_equals($storedPassword, $plainPassword)) {
        return false;
    }

    $newHash = password_hash($plainPassword, PASSWORD_DEFAULT);
    $stmt = $pdo->prepare('UPDATE users SET password = ? WHERE id = ?');
    $stmt->execute([$newHash, $user['id']]);
    $user['password'] = $newHash;

    return true;
}

// Funkcja do sprawdzania i zarządzania limitami logowania
function checkLoginAttempts($pdo, $ip) {
    try {
        if (!tableExists($pdo, 'login_attempts')) {
            $pdo->exec("CREATE TABLE IF NOT EXISTS login_attempts (
                id INT AUTO_INCREMENT PRIMARY KEY,
                ip_address VARCHAR(45) NOT NULL,
                attempt_time DATETIME NOT NULL,
                INDEX idx_ip_time (ip_address, attempt_time)
            )");
        }

        if (!tableExists($pdo, 'login_attempts')) {
            return ['blocked' => false];
        }

        $pdo->prepare("DELETE FROM login_attempts WHERE attempt_time < DATE_SUB(NOW(), INTERVAL 1 HOUR)")->execute();

        $stmt = $pdo->prepare("
            SELECT COUNT(*) as attempts, MAX(attempt_time) as last_attempt 
            FROM login_attempts 
            WHERE ip_address = ? AND attempt_time > DATE_SUB(NOW(), INTERVAL 5 MINUTE)
        ");
        $stmt->execute([$ip]);
        $block_check = $stmt->fetch(PDO::FETCH_ASSOC);

        if ((int) ($block_check['attempts'] ?? 0) >= 5) {
            $lastAttempt = isset($block_check['last_attempt']) ? strtotime((string) $block_check['last_attempt']) : false;
            $secondsLeft = $lastAttempt ? max(1, 300 - (time() - $lastAttempt)) : 300;
            $minutesLeft = ceil($secondsLeft / 60);
            return [
                'blocked' => true,
                'message' => "Zbyt wiele nieudanych prób logowania. Spróbuj ponownie za {$minutesLeft} minut.",
                'time_left' => $secondsLeft
            ];
        }

        $stmt = $pdo->prepare("
            SELECT COUNT(*) as attempts 
            FROM login_attempts 
            WHERE ip_address = ? AND attempt_time > DATE_SUB(NOW(), INTERVAL 1 MINUTE)
        ");
        $stmt->execute([$ip]);
        $recent_attempts = $stmt->fetch(PDO::FETCH_ASSOC);

        if ((int) ($recent_attempts['attempts'] ?? 0) >= 5) {
            return [
                'blocked' => true,
                'message' => "Zbyt wiele prób logowania. Poczekaj minutę przed ponowną próbą.",
                'time_left' => 60
            ];
        }
    } catch (Throwable $e) {
        return ['blocked' => false];
    }

    return ['blocked' => false];
}

// Funkcja do zapisania nieudanej próby logowania
function recordFailedAttempt($pdo, $ip) {
    try {
        if (!tableExists($pdo, 'login_attempts')) {
            return;
        }

        $stmt = $pdo->prepare("INSERT INTO login_attempts (ip_address, attempt_time) VALUES (?, NOW())");
        $stmt->execute([$ip]);
    } catch (Throwable $e) {
    }
}

// Funkcja do wyczyszczenia prób po udanym logowaniu
function clearLoginAttempts($pdo, $ip) {
    try {
        if (!tableExists($pdo, 'login_attempts')) {
            return;
        }

        $stmt = $pdo->prepare("DELETE FROM login_attempts WHERE ip_address = ?");
        $stmt->execute([$ip]);
    } catch (Throwable $e) {
    }
}

// Pobierz IP użytkownika
$ip_address = $_SERVER['REMOTE_ADDR'];
if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
    $ip_address = explode(',', $_SERVER['HTTP_X_FORWARDED_FOR'])[0];
}

// Sprawdź limity logowania
$attempt_check = checkLoginAttempts($pdo, $ip_address);
if ($attempt_check['blocked']) {
    header('Location: /login/?error=' . urlencode($attempt_check['message']));
    exit();
}

if ($_SERVER["REQUEST_METHOD"] !== "POST") {
    header('Location: /login/?error=' . urlencode('Nieprawidłowa metoda żądania'));
    exit();
}

$email = trim($_POST["email"] ?? "");
$password = $_POST["password"] ?? "";

if (empty($email) || empty($password)) {
    recordFailedAttempt($pdo, $ip_address);
    header('Location: /login/?error=' . urlencode('Email i hasło są wymagane'));
    exit();
}

// Sprawdzenie czy użytkownik istnieje
$user = getLoginUserByEmail($pdo, $email);

if (!$user) {
    recordFailedAttempt($pdo, $ip_address);
    header('Location: /login/?error=' . urlencode('Nieprawidłowy email lub hasło'));
    exit();
}

// Weryfikacja hasła
if (!verifyAndUpgradePassword($pdo, $user, $password)) {
    recordFailedAttempt($pdo, $ip_address);
    header('Location: /login/?error=' . urlencode('Nieprawidłowy email lub hasło'));
    exit();
}

// Sprawdzenie czy konto nie jest wyłączone (disabled)
if ($user['disabled'] == 1) {
    recordFailedAttempt($pdo, $ip_address);
    header('Location: /login/?error=' . urlencode('Nieprawidłowy email lub hasło'));
    exit();
}

// Sprawdzenie czy email jest zweryfikowany
if ($user['email_verified'] != 1) {
    header('Location: /login/verify.php?email=' . urlencode($email) . '&error=' . urlencode('Twój email nie został jeszcze zweryfikowany'));
    exit();
}

// Logowanie udane - wyczyść próby logowania dla tego IP
clearLoginAttempts($pdo, $ip_address);

// Logowanie udane - ustawienie sesji
session_regenerate_id(true);
$_SESSION['logged_in'] = true;
$_SESSION['user_id'] = $user['id'];
$_SESSION['username'] = $user['username'];
$_SESSION['email'] = $user['email'];
$_SESSION['role'] = $user['role'] ?? 'user';
$_SESSION['remember_me'] = false;
$_SESSION['last_activity'] = time();

// Obsługa "Zapamiętaj mnie"
if (isset($_POST['remember']) && $_POST['remember'] === 'on') {
    try {
        if (og_session_ensure_remember_tokens_table($pdo)) {
            $token = bin2hex(random_bytes(32));
            $tokenHash = hash('sha256', $token);
            $expiresAt = date('Y-m-d H:i:s', time() + OG_SESSION_TIMEOUT_REMEMBER);

            $pdo->prepare('DELETE FROM remember_tokens WHERE user_id = ?')->execute([$user['id']]);
            $stmt = $pdo->prepare('INSERT INTO remember_tokens (user_id, token, expires_at) VALUES (?, ?, ?)');
            $stmt->execute([$user['id'], $tokenHash, $expiresAt]);

            $_SESSION['remember_me'] = true;
            og_session_refresh_cookie('remember_token', $token, OG_SESSION_TIMEOUT_REMEMBER);
        }
    } catch (Throwable $e) {
        $_SESSION['remember_me'] = false;
    }
}

// Nagłówki zapobiegające cachowaniu
header('Cache-Control: no-store, no-cache, must-revalidate, max-age=0');
header('Pragma: no-cache');

// Przekierowanie - admini do panelu, zwykli użytkownicy na stronę główną
if ($_SESSION['role'] === 'admin') {
    header('Location: /administration/');
} else {
    header('Location: /home/');
}
exit();
