"""Offline-verifiable, device-bound licence helpers for Shop Manager POS."""
import base64
import hashlib
import json
import os
import platform
import uuid
from datetime import datetime, timedelta

from cryptography.exceptions import InvalidSignature
from cryptography.hazmat.primitives import serialization
from cryptography.hazmat.primitives.asymmetric.ed25519 import Ed25519PublicKey

from models import LicenseInstallation, db, bangladesh_time


TRIAL_DAYS = 7


def _machine_id():
    """Stable Windows value where available, with safe cross-platform fallback."""
    if os.name == "nt":
        try:
            import winreg
            with winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\Microsoft\Cryptography") as key:
                return winreg.QueryValueEx(key, "MachineGuid")[0]
        except OSError:
            pass
    return f"{platform.node()}:{uuid.getnode()}:{platform.system()}"


def device_hash(installation_id):
    raw = f"{_machine_id()}:{installation_id}".encode("utf-8")
    return hashlib.sha256(raw).hexdigest()


def get_installation():
    state = LicenseInstallation.query.order_by(LicenseInstallation.id.asc()).first()
    if state:
        return state
    installation_id = uuid.uuid4().hex
    now = bangladesh_time()
    state = LicenseInstallation(
        installation_id=installation_id,
        device_hash=device_hash(installation_id),
        trial_started_at=now,
        trial_expires_at=now + timedelta(days=TRIAL_DAYS),
    )
    db.session.add(state)
    db.session.commit()
    return state


def activation_request_code(state=None):
    state = state or get_installation()
    return f"POS1.{state.installation_id}.{state.device_hash}"


def _decode_token(token):
    try:
        encoded_payload, encoded_signature = token.strip().split(".", 1)
        payload_bytes = base64.urlsafe_b64decode(encoded_payload + "=" * (-len(encoded_payload) % 4))
        signature = base64.urlsafe_b64decode(encoded_signature + "=" * (-len(encoded_signature) % 4))
        return encoded_payload, payload_bytes, signature, json.loads(payload_bytes.decode("utf-8"))
    except (ValueError, UnicodeDecodeError, json.JSONDecodeError):
        return None


def verify_license_token(token, expected_device_hash, public_key_path):
    decoded = _decode_token(token)
    if not decoded or not os.path.exists(public_key_path):
        return False, "Invalid activation key."
    encoded_payload, payload_bytes, signature, payload = decoded
    try:
        with open(public_key_path, "rb") as key_file:
            public_key = serialization.load_pem_public_key(key_file.read())
        if not isinstance(public_key, Ed25519PublicKey):
            return False, "Invalid licence public key."
        public_key.verify(signature, payload_bytes)
        expires_at = datetime.fromisoformat(payload["expires_at"])
        if payload.get("device_hash") != expected_device_hash:
            return False, "This key belongs to another device."
        if expires_at < bangladesh_time():
            return False, "This licence has expired."
        return True, payload
    except (InvalidSignature, KeyError, ValueError, OSError):
        return False, "Invalid activation key."


def licence_status(public_key_path, enforcement_enabled):
    """Return status without blocking local development before a public key exists."""
    state = get_installation()
    if state.license_token:
        valid, result = verify_license_token(state.license_token, state.device_hash, public_key_path)
        if valid:
            state.last_validated_at = bangladesh_time()
            db.session.commit()
            return "licensed", result, state
    if not enforcement_enabled:
        return "development", None, state
    if bangladesh_time() <= state.trial_expires_at:
        return "trial", None, state
    return "expired", None, state
