<?php

declare(strict_types=1);

namespace SeoScope\Auth;

use SeoScope\Http\Request;

final class SessionAuth
{
    public const SESSION_NAME = 'SEOSCOPE_ADMIN';

    public static function start(): void
    {
        if (session_status() === PHP_SESSION_ACTIVE) {
            return;
        }
        // Harden session handling on shared hosting.
        // These settings are safe defaults and reduce session fixation risks.
        @ini_set('session.use_only_cookies', '1');
        @ini_set('session.use_strict_mode', '1');
        @ini_set('session.cookie_httponly', '1');
        @ini_set('session.cookie_samesite', 'Lax');
        session_save_path(self::resolveSessionSavePath());

        $cookiePath = '/';
        $config = $GLOBALS['seoscope_config'] ?? [];
        if (is_array($config)) {
            $app = $config['app'] ?? [];
            $raw = trim((string) ($app['base_path'] ?? ''), '/');
            if ($raw !== '') {
                $cookiePath = '/' . $raw . '/';
            }
        }

        session_name(self::SESSION_NAME);
        session_set_cookie_params([
            'lifetime' => 0,
            'path' => $cookiePath,
            'secure' => Request::isHttps(),
            'httponly' => true,
            'samesite' => 'Lax',
        ]);
        session_start();
    }

    /**
     * Prefer project storage (inside open_basedir on typical Plesk setups). PHP's
     * default session path is often outside open_basedir, which breaks sessions.
     */
    private static function resolveSessionSavePath(): string
    {
        if (!defined('SEOSCOPE_ROOT')) {
            $ini = ini_get('session.save_path');
            return ($ini !== '' && is_string($ini)) ? $ini : sys_get_temp_dir();
        }
        $primary = SEOSCOPE_ROOT . '/storage/sessions';
        if (!is_dir($primary)) {
            @mkdir($primary, 0770, true);
        }
        if (is_dir($primary) && is_writable($primary)) {
            return $primary;
        }
        $suffix = substr(hash('sha256', SEOSCOPE_ROOT), 0, 16);
        $fallback = rtrim(sys_get_temp_dir(), '/') . '/seoscope-sess-' . $suffix;
        if (!is_dir($fallback)) {
            @mkdir($fallback, 0770, true);
        }
        if (is_dir($fallback) && is_writable($fallback)) {
            return $fallback;
        }
        $ini = ini_get('session.save_path');
        return ($ini !== '' && is_string($ini) && is_writable($ini)) ? $ini : sys_get_temp_dir();
    }

    /**
     * @param array{id:int,email:string,name:?string} $user
     */
    public static function login(array $user): void
    {
        self::start();
        session_regenerate_id(true);
        $_SESSION['user_id'] = $user['id'];
        $_SESSION['user_email'] = $user['email'];
        $_SESSION['user_name'] = $user['name'];
    }

    public static function logout(): void
    {
        self::start();
        $_SESSION = [];
        if (ini_get('session.use_cookies')) {
            $p = session_get_cookie_params();
            setcookie(session_name(), '', time() - 42000, $p['path'], $p['domain'], $p['secure'], $p['httponly']);
        }
        session_destroy();
    }

    public static function check(): bool
    {
        self::start();
        return isset($_SESSION['user_id']) && is_numeric($_SESSION['user_id']);
    }

    /**
     * @return array{id:int,email:string,name:?string}|null
     */
    public static function user(): ?array
    {
        if (!self::check()) {
            return null;
        }
        return [
            'id' => (int) $_SESSION['user_id'],
            'email' => (string) $_SESSION['user_email'],
            'name' => isset($_SESSION['user_name']) ? (string) $_SESSION['user_name'] : null,
        ];
    }
}
