# Familiar - Self-Hosted AI Companion Platform
# Copyright (c) 2026 George Scott Foley
# ORCID: 0009-0006-4957-0540
# Email: Georgescottfoley@proton.me
# Licensed under the MIT License - see LICENSE file for details

"""
Genesis Block Bridge Layer

Connects the training skill's off-chain provenance system to the
on-chain genesis block provenance chain. Each chain-of-custody entry
and dataset export is anchored as a signed block.

Bridge functions are no-ops if no genesis block exists yet — this
allows the training skill to operate normally before genesis creation.
"""

import hashlib
import logging
from datetime import datetime, timezone

logger = logging.getLogger(__name__)


def _get_chain_dir():
    """Get chain directory (tenant-scoped in Reflection, default in standalone)."""
    try:
        from familiar.core.paths import CHAIN_DIR

        return CHAIN_DIR
    except ImportError:
        from pathlib import Path

        return Path.home() / ".familiar" / "data" / "chain"


def _get_store():
    """Get or create the ChainStore singleton for this session."""
    from familiar.core.genesis import ChainStore

    chain_dir = _get_chain_dir()
    chain_dir.mkdir(parents=True, exist_ok=True)
    return ChainStore(chain_dir / "chain.db")


def _get_keypair():
    """Load or create the RSA keypair."""
    from familiar.core.genesis import load_or_create_keypair

    key_dir = _get_chain_dir() / "keys"
    return load_or_create_keypair(key_dir)


def create_familiar_genesis(
    owner_name: str,
    owner_orcid: str,
    owner_email: str = "",
    expertise_domains: dict = None,
    template_source: str = "familiar_v1.4.0",
) -> str:
    """
    Create a genesis block for this Familiar instance.

    Returns the genesis block hash.
    Raises RuntimeError if a genesis block already exists (immutable — patent constraint).
    """
    from familiar.core.genesis import (
        ChainBlock,
        GenesisBlock,
        ProfessionalCredentialAnchor,
        ProfessionalOwnershipFramework,
        ProfessionalTemplateDerivation,
        ProvenanceChainInit,
        VerifiedCapabilityAttestation,
    )

    store = _get_store()

    if store.get_genesis() is not None:
        raise RuntimeError(
            "Genesis block already exists. The genesis block is immutable "
            "per patent constraint — it cannot be replaced or recreated."
        )

    private_key, public_key = _get_keypair()
    now = datetime.now(timezone.utc).isoformat()

    # Build credential hash from owner identity
    cred_bundle = f"{owner_name}:{owner_orcid}:{owner_email}"
    credential_hash = hashlib.sha256(cred_bundle.encode()).hexdigest()

    # (a) PCA
    pca = ProfessionalCredentialAnchor(
        credential_hash=credential_hash,
        authority_signatures=[],
        competency_metadata={"owner_name": owner_name, "email": owner_email},
        regulatory_attestations=[],
        orcid=owner_orcid,
    )

    # (b) PTD
    ptd = ProfessionalTemplateDerivation(
        template_source_id=template_source,
        customization_params={"platform": "familiar", "version": "1.4.0"},
        individualization_sigs=[],
        evolution_provenance=[template_source],
    )

    # (c) VCA
    domains = expertise_domains or {"ai_curation": ["training_data", "provenance"]}
    vca = VerifiedCapabilityAttestation(
        expertise_domains=domains,
        quality_thresholds={"min_curation_quality": 0.5},
        standard_refs=[],
        validation_proofs=[],
    )

    # (d) POF — single-owner control
    from cryptography.hazmat.primitives.serialization import Encoding, PublicFormat

    pub_pem = public_key.public_bytes(Encoding.PEM, PublicFormat.SubjectPublicKeyInfo)
    pof = ProfessionalOwnershipFramework(
        multi_sig_control={"owner": pub_pem.decode()},
        operator_authorization={"owner_name": owner_name, "orcid": owner_orcid},
        succession_params={},
        delegation_matrix={"owner": ["full_control"]},
    )

    # (e) PCI
    pci = ProvenanceChainInit(
        creation_timestamp=now,
        witness_proofs=[],
        authorization_sigs=[],
        audit_anchors=[],
    )

    # Build, hash, and sign the genesis block
    genesis = GenesisBlock(pca=pca, ptd=ptd, vca=vca, pof=pof, pci=pci)
    genesis.compute_hash()
    genesis.sign(private_key)

    # Wrap as ChainBlock index 0
    chain_block = ChainBlock(
        index=0,
        timestamp=now,
        prev_hash="0" * 64,
        block_hash="",
        block_type="genesis",
        payload=genesis.to_dict(),
    )
    chain_block.compute_hash()
    chain_block.sign(private_key)

    store.append(chain_block)
    logger.info("Genesis block created: %s", chain_block.block_hash[:16])
    return chain_block.block_hash


def anchor_provenance(custody_entry: dict) -> str:
    """
    Anchor a chain-of-custody entry from _record_provenance() to the chain.

    Returns the new block hash, or empty string if no genesis exists.
    """
    from familiar.core.genesis import ChainBlock

    store = _get_store()
    genesis = store.get_genesis()
    if genesis is None:
        return ""

    private_key, _ = _get_keypair()
    latest = store.get_latest()
    now = datetime.now(timezone.utc).isoformat()

    block = ChainBlock(
        index=latest.index + 1,
        timestamp=now,
        prev_hash=latest.block_hash,
        block_hash="",
        block_type="provenance",
        payload=custody_entry,
    )
    block.compute_hash()
    block.sign(private_key)
    store.append(block)

    logger.debug("Anchored provenance block %d: %s", block.index, block.block_hash[:16])
    return block.block_hash


def anchor_export(export_meta: dict) -> str:
    """
    Anchor a dataset export (with its SHA-256 fingerprint) to the chain.

    Returns the new block hash, or empty string if no genesis exists.
    """
    from familiar.core.genesis import ChainBlock

    store = _get_store()
    genesis = store.get_genesis()
    if genesis is None:
        return ""

    private_key, _ = _get_keypair()
    latest = store.get_latest()
    now = datetime.now(timezone.utc).isoformat()

    block = ChainBlock(
        index=latest.index + 1,
        timestamp=now,
        prev_hash=latest.block_hash,
        block_hash="",
        block_type="export",
        payload=export_meta,
    )
    block.compute_hash()
    block.sign(private_key)
    store.append(block)

    logger.debug("Anchored export block %d: %s", block.index, block.block_hash[:16])
    return block.block_hash


def get_chain_status() -> dict:
    """
    Return chain summary: genesis hash, length, latest block, integrity check.
    """
    store = _get_store()
    genesis = store.get_genesis()

    if genesis is None:
        return {
            "initialized": False,
            "genesis_hash": None,
            "chain_length": 0,
            "latest_block": None,
            "integrity": None,
        }

    latest = store.get_latest()
    valid, error = store.verify_chain()

    return {
        "initialized": True,
        "genesis_hash": genesis.block_hash,
        "chain_length": store.chain_length(),
        "latest_block": {
            "index": latest.index,
            "type": latest.block_type,
            "hash": latest.block_hash,
            "timestamp": latest.timestamp,
        }
        if latest
        else None,
        "integrity": {"valid": valid, "error": error},
    }
