<?php

if (!defined('ABSPATH')) { exit; }

class AIEO_SSO_State {

    const COOKIE_NAME = 'aieo_sso_state';
    const TTL_SECONDS = 600; 
    const SECRET_OPT  = 'aieo_social_login_signing_secret';

    
    public static function issue($intent, $redirect_to, $user_id = 0) {
        $payload = array(
            'nonce'       => bin2hex(random_bytes(8)),
            'intent'      => sanitize_key((string) $intent),
            'redirect_to' => esc_url_raw((string) $redirect_to),
            'iat'         => time(),
            'uid'         => (int) $user_id,
        );
        $token = self::base64url_encode(wp_json_encode($payload));
        $sig   = self::sign($token);
        $signed = $token . '.' . $sig;

        
        setcookie(
            self::COOKIE_NAME,
            $signed,
            array(
                'expires'  => time() + self::TTL_SECONDS,
                'path'     => '/',
                'domain'   => '',
                'secure'   => is_ssl(),
                'httponly' => true,
                'samesite' => 'Lax',
            )
        );
        return $signed;
    }

    
    public static function verify($state_from_query) {
        $state_from_query = (string) $state_from_query;
        if ($state_from_query === '') {
            return new WP_Error('sso_state_missing', 'state parameter missing.');
        }
        $cookie = isset($_COOKIE[self::COOKIE_NAME]) ? (string) wp_unslash($_COOKIE[self::COOKIE_NAME]) : '';
        if ($cookie === '' || !hash_equals($cookie, $state_from_query)) {
            return new WP_Error('sso_state_mismatch', 'state cookie does not match query state.');
        }
        $parts = explode('.', $state_from_query, 2);
        if (count($parts) !== 2) {
            return new WP_Error('sso_state_format', 'malformed state token.');
        }
        list($token, $sig) = $parts;
        $expected = self::sign($token);
        if (!hash_equals($expected, (string) $sig)) {
            return new WP_Error('sso_state_signature', 'invalid state signature.');
        }
        $payload = json_decode(self::base64url_decode($token), true);
        if (!is_array($payload)) {
            return new WP_Error('sso_state_payload', 'invalid state payload.');
        }
        if (empty($payload['iat']) || (time() - (int) $payload['iat']) > self::TTL_SECONDS) {
            return new WP_Error('sso_state_expired', 'state token expired.');
        }

        
        self::clear();
        return $payload;
    }

    public static function clear() {
        setcookie(self::COOKIE_NAME, '', array(
            'expires'  => time() - 3600,
            'path'     => '/',
            'secure'   => is_ssl(),
            'httponly' => true,
            'samesite' => 'Lax',
        ));
    }

    
    private static function get_secret() {
        $secret = (string) get_option(self::SECRET_OPT, '');
        if (strlen($secret) >= 64) { return $secret; }
        $secret = bin2hex(random_bytes(32));
        update_option(self::SECRET_OPT, $secret, false);
        return $secret;
    }

    private static function sign($token) {
        return hash_hmac('sha256', (string) $token, self::get_secret());
    }

    private static function base64url_encode($s) {
        return rtrim(strtr(base64_encode((string) $s), '+/', '-_'), '=');
    }

    private static function base64url_decode($s) {
        $s = strtr((string) $s, '-_', '+/');
        $pad = strlen($s) % 4;
        if ($pad) { $s .= str_repeat('=', 4 - $pad); }
        $out = base64_decode($s, true);
        return $out === false ? '' : $out;
    }
}
