<?php

declare(strict_types=1);

namespace Flowaxy\Infrastructure\Persistence\Repositories;

use Flowaxy\Domain\User\Entities\User;
use Flowaxy\Domain\User\Services\UserRepositoryInterface;
use Flowaxy\Support\Facades\Log;
use PDO;
use PDOException;
use InvalidArgumentException;
use Throwable;

// Репозиторий для пользователей
final class UserRepository extends AbstractRepository implements UserRepositoryInterface
{
    protected string $tableName = 'users';

    // Найти пользователя по имени
    public function findByUsername(string $username): ?User
    {
        if ($this->connection === null) {
            return null;
        }

        try {
            $stmt = $this->connection->prepare("SELECT * FROM {$this->tableName} WHERE username = ?");
            $stmt->execute([$username]);
            $row = $stmt->fetch(PDO::FETCH_ASSOC);
            return $row ? $this->mapToEntity($row) : null;
        } catch (PDOException $e) {
            try {
                Log::Error('Помилка пошуку користувача за іменем', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return null;
        }
    }

    // Преобразовать строку БД в сущность
    protected function mapToEntity(array $row): User
    {
        return new User(
            id: (int)$row['id'],
            username: (string)$row['username'],
            passwordHash: (string)$row['password_hash'],
            sessionToken: $row['session_token'] ?? null,
            lastActivity: $row['last_activity'] ?? null,
            isActive: (bool)($row['is_active'] ?? true)
        );
    }

    // Преобразовать сущность в массив для БД
    protected function mapFromEntity(object $entity): array
    {
        if (!$entity instanceof User) {
            throw new InvalidArgumentException('Entity must be an instance of User');
        }

        return [
            'id' => $entity->id,
            'username' => $entity->username,
            'password_hash' => $entity->passwordHash,
            'session_token' => $entity->sessionToken,
            'last_activity' => $entity->lastActivity,
            'is_active' => $entity->isActive ? 1 : 0,
        ];
    }

    // Найти пользователя по ID
    public function findById(int $id): ?User
    {
        $user = $this->find($id);
        return $user instanceof User ? $user : null;
    }

    // Обновить сессию пользователя
    public function updateSession(int $userId, string $token, string $lastActivity): bool
    {
        if ($this->connection === null) {
            return false;
        }

        try {
            $stmt = $this->connection->prepare(
                "UPDATE {$this->tableName} SET session_token = ?, last_activity = ? WHERE id = ?"
            );
            return $stmt->execute([$token, $lastActivity, $userId]);
        } catch (PDOException $e) {
            try {
                Log::Error('Помилка оновлення сесії користувача', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    // Очистить сессию пользователя
    public function clearSession(int $userId): bool
    {
        return $this->updateSession($userId, '', '');
    }

    // Пометить пользователя как неактивного
    public function markInactive(int $userId): bool
    {
        if ($this->connection === null) {
            return false;
        }

        try {
            $stmt = $this->connection->prepare(
                "UPDATE {$this->tableName} SET is_active = 0 WHERE id = ?"
            );
            return $stmt->execute([$userId]);
        } catch (PDOException $e) {
            try {
                Log::Error('Помилка деактивації користувача', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }

    // Обновить время последней активности
    public function updateLastActivity(int $userId, string $timestamp): bool
    {
        if ($this->connection === null) {
            return false;
        }

        try {
            $stmt = $this->connection->prepare(
                "UPDATE {$this->tableName} SET last_activity = ? WHERE id = ?"
            );
            return $stmt->execute([$timestamp, $userId]);
        } catch (PDOException $e) {
            try {
                Log::Error('Помилка оновлення останньої активності користувача', ['exception' => $e]);
            } catch (Throwable $logError) {
                // Ignore logging errors
            }
            return false;
        }
    }
}
