<?php

declare(strict_types=1);

namespace App\Framework\Http\Session;

use App\Framework\Http\IpAddress;
use App\Framework\Http\Session\ValueObjects\FlashMessage;
use App\Framework\Http\Session\ValueObjects\FlashMessageType;
use App\Framework\Http\Session\ValueObjects\FormData;
use App\Framework\Http\Session\ValueObjects\ValidationError;

/**
 * Example class demonstrating SessionData Value Object usage
 * This shows how to work with structured session data instead of raw arrays
 */
final readonly class SessionDataExample
{
    public function __construct(
        private Session $session
    ) {
    }

    /**
     * Example: Working with form data using Value Objects
     */
    public function handleFormSubmission(string $formId, array $formFields): void
    {
        // Create form data with metadata
        $formData = FormData::create($formFields, [
            'submitted_at' => time(),
            'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? 'unknown',
        ]);

        // Update session using Value Objects
        $this->session->updateSessionData(function ($sessionData) use ($formId, $formData) {
            return $sessionData->withFormData(
                $sessionData->formData->with($formId, $formData)
            );
        });
    }

    /**
     * Example: Working with validation errors using Value Objects
     */
    public function addValidationErrors(string $formId, array $errors): void
    {
        $validationErrors = [];
        foreach ($errors as $field => $messages) {
            foreach ((array) $messages as $message) {
                $validationErrors[] = ValidationError::create($field, $message, [
                    'severity' => 'error',
                    'form_id' => $formId,
                ]);
            }
        }

        $this->session->updateSessionData(function ($sessionData) use ($formId, $validationErrors) {
            $collection = $sessionData->validationErrors;
            foreach ($validationErrors as $error) {
                $collection = $collection->withError($formId, $error);
            }

            return $sessionData->withValidationErrors($collection);
        });
    }

    /**
     * Example: Working with flash messages using Value Objects
     */
    public function addFlashMessages(): void
    {
        $this->session->updateSessionData(function ($sessionData) {
            return $sessionData->withFlashMessages(
                $sessionData->flashMessages
                    ->addSuccess('Operation completed successfully!')
                    ->addWarning('Please verify your email address')
                    ->addInfo('New features are available')
            );
        });
    }

    /**
     * Example: Working with security data using Value Objects
     */
    public function updateSecurityData(IpAddress $clientIp): void
    {
        $csrfToken = bin2hex(random_bytes(32));
        $sessionFingerprint = hash('sha256', $_SERVER['HTTP_USER_AGENT'] . $clientIp->toString());

        $this->session->updateSessionData(function ($sessionData) use ($csrfToken, $sessionFingerprint, $clientIp) {
            return $sessionData->withSecurityData(
                $sessionData->securityData
                    ->withCsrfToken($csrfToken, $clientIp)
                    ->withSessionFingerprint($sessionFingerprint, $clientIp)
                    ->resetLoginAttempts()
            );
        });
    }

    /**
     * Example: Reading structured session data
     */
    public function displaySessionInfo(): array
    {
        $sessionData = $this->session->getSessionData();

        return [
            'user_data' => $sessionData->userData,
            'has_form_data' => ! $sessionData->formData->isEmpty(),
            'validation_errors_count' => $sessionData->validationErrors->count(),
            'flash_messages_by_type' => [
                'success' => $sessionData->flashMessages->countByType(FlashMessageType::SUCCESS),
                'error' => $sessionData->flashMessages->countByType(FlashMessageType::ERROR),
                'warning' => $sessionData->flashMessages->countByType(FlashMessageType::WARNING),
                'info' => $sessionData->flashMessages->countByType(FlashMessageType::INFO),
            ],
            'security_info' => [
                'has_csrf_token' => $sessionData->securityData->has('csrf_token'),
                'login_attempts' => $sessionData->securityData->getLoginAttempts(),
                'has_session_fingerprint' => $sessionData->securityData->has('session_fingerprint'),
            ],
            'total_size_estimate' => $sessionData->getEstimatedSize(),
            'is_empty' => $sessionData->isEmpty(),
        ];
    }

    /**
     * Example: Cleaning up old session data
     */
    public function cleanupOldData(): void
    {
        $this->session->updateSessionData(function ($sessionData) {
            // Remove flash messages older than 1 hour
            $cleanFlashMessages = $sessionData->flashMessages->removeOldMessages(3600);

            // Remove expired security data
            $cleanSecurityData = $sessionData->securityData->removeExpired();

            return $sessionData
                ->withFlashMessages($cleanFlashMessages)
                ->withSecurityData($cleanSecurityData);
        });
    }

    /**
     * Example: Working with user data through SessionData
     */
    public function manageUserData(): void
    {
        // Using the new user data methods
        $this->session->setUserData('user_id', 123);
        $this->session->setUserData('username', 'john_doe');
        $this->session->setUserData('preferences', ['theme' => 'dark', 'language' => 'en']);

        // Reading user data
        $userId = $this->session->getUserData('user_id');
        $username = $this->session->getUserData('username', 'anonymous');
        $theme = $this->session->getUserData('preferences')['theme'] ?? 'light';

        // Check existence
        if ($this->session->hasUserData('user_id')) {
            // User is logged in
        }

        // Remove user data
        $this->session->removeUserData('temporary_token');
    }

    /**
     * Example: Complex session operation with multiple updates
     */
    public function handleComplexOperation(string $formId, array $formData, array $errors = []): void
    {
        $this->session->updateSessionData(function ($sessionData) use ($formId, $formData, $errors) {
            $updatedData = $sessionData;

            // Add form data
            if (! empty($formData)) {
                $formDataObj = FormData::create($formData, ['operation' => 'complex']);
                $updatedData = $updatedData->withFormData(
                    $updatedData->formData->with($formId, $formDataObj)
                );
            }

            // Add validation errors if any
            if (! empty($errors)) {
                $validationCollection = $updatedData->validationErrors;
                foreach ($errors as $field => $messages) {
                    foreach ((array) $messages as $message) {
                        $error = ValidationError::create($field, $message);
                        $validationCollection = $validationCollection->withError($formId, $error);
                    }
                }
                $updatedData = $updatedData->withValidationErrors($validationCollection);
            }

            // Add appropriate flash message
            $flashMessage = empty($errors)
                ? FlashMessage::success('Operation completed successfully!')
                : FlashMessage::error('Please correct the errors below');

            $updatedData = $updatedData->withFlashMessages(
                $updatedData->flashMessages->add($flashMessage)
            );

            return $updatedData;
        });
    }
}
