"""Tests for HWID activation token -- Sprint 8."""

from __future__ import annotations

import hashlib
import hmac
import os

import pytest

from arautopilot.core.hwid import (
    STUB_SECRET_KEY,
    TOKEN_BYTES,
    format_hwid,
    generate_token,
    hwid_from_mac_words,
    verify_token,
)


SAMPLE_HWID = "aabbccddeeff"   # 12-char lower-case hex


class TestHwidFromMacWords:
    def test_known_bytes(self):
        # mac01=0xAABB, mac23=0xCCDD, mac45=0xEEFF → "aabbccddeeff"
        result = hwid_from_mac_words(0xAABB, 0xCCDD, 0xEEFF)
        assert result == "aabbccddeeff"

    def test_zero_mac(self):
        result = hwid_from_mac_words(0, 0, 0)
        assert result == "000000000000"

    def test_all_ones(self):
        result = hwid_from_mac_words(0xFFFF, 0xFFFF, 0xFFFF)
        assert result == "ffffffffffff"

    def test_returns_lowercase(self):
        result = hwid_from_mac_words(0xAABB, 0xCCDD, 0xEEFF)
        assert result == result.lower()

    def test_result_is_12_chars(self):
        result = hwid_from_mac_words(0x0102, 0x0304, 0x0506)
        assert len(result) == 12

    def test_byte_order(self):
        # 0x1234 → bytes [0x12, 0x34]
        result = hwid_from_mac_words(0x1234, 0x0000, 0x0000)
        assert result[:4] == "1234"


class TestGenerateToken:
    def test_returns_32_hex_chars(self):
        token = generate_token(SAMPLE_HWID)
        assert len(token) == TOKEN_BYTES * 2  # 32
        assert all(c in "0123456789abcdef" for c in token.lower())

    def test_deterministic_with_stub_key(self, monkeypatch):
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        t1 = generate_token(SAMPLE_HWID)
        t2 = generate_token(SAMPLE_HWID)
        assert t1 == t2

    def test_different_hwid_different_token(self, monkeypatch):
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        t1 = generate_token("aabbccddeeff")
        t2 = generate_token("112233445566")
        assert t1 != t2

    def test_uses_env_key_when_set(self, monkeypatch):
        monkeypatch.setenv("AR_ACTIVATION_KEY", "test-production-key")
        prod_token = generate_token(SAMPLE_HWID)
        monkeypatch.delenv("AR_ACTIVATION_KEY")
        stub_token = generate_token(SAMPLE_HWID)
        assert prod_token != stub_token

    def test_case_insensitive_hwid(self, monkeypatch):
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        t_lower = generate_token("aabbccddeeff")
        t_upper = generate_token("AABBCCDDEEFF")
        assert t_lower == t_upper

    def test_matches_manual_hmac(self, monkeypatch):
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        expected = hmac.new(
            STUB_SECRET_KEY, SAMPLE_HWID.encode(), hashlib.sha256
        ).hexdigest()[:TOKEN_BYTES * 2]
        assert generate_token(SAMPLE_HWID) == expected


class TestVerifyToken:
    def test_valid_token_returns_true(self, monkeypatch):
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        token = generate_token(SAMPLE_HWID)
        assert verify_token(SAMPLE_HWID, token) is True

    def test_wrong_token_returns_false(self, monkeypatch):
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        assert verify_token(SAMPLE_HWID, "a" * 32) is False

    def test_wrong_hwid_returns_false(self, monkeypatch):
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        token = generate_token(SAMPLE_HWID)
        assert verify_token("000000000000", token) is False

    def test_case_insensitive_token_comparison(self, monkeypatch):
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        token = generate_token(SAMPLE_HWID)
        assert verify_token(SAMPLE_HWID, token.upper()) is True

    def test_constant_time_compare(self, monkeypatch):
        """verify_token must use hmac.compare_digest (checked by smoke-test, not timing)."""
        monkeypatch.delenv("AR_ACTIVATION_KEY", raising=False)
        token = generate_token(SAMPLE_HWID)
        # Calling with correct and incorrect tokens both return without exception
        assert verify_token(SAMPLE_HWID, token) is True
        assert verify_token(SAMPLE_HWID, "x" * 32) is False


class TestFormatHwid:
    def test_formats_correctly(self):
        result = format_hwid("aabbccddeeff")
        assert result == "AA:BB:CC:DD:EE:FF"

    def test_uppercase_output(self):
        result = format_hwid("aabbccddeeff")
        assert result == result.upper().replace("X", ":")  # colons preserved
        assert result == "AA:BB:CC:DD:EE:FF"

    def test_colon_separated_6_groups(self):
        result = format_hwid("112233445566")
        parts = result.split(":")
        assert len(parts) == 6
        assert all(len(p) == 2 for p in parts)

    def test_invalid_length_raises(self):
        with pytest.raises(ValueError, match="12 hex chars"):
            format_hwid("aabb")

    def test_all_zeros(self):
        assert format_hwid("000000000000") == "00:00:00:00:00:00"

    def test_all_ff(self):
        assert format_hwid("ffffffffffff") == "FF:FF:FF:FF:FF:FF"
