"""
HORUS Message Builder - Compile Generated Messages

Builds the generated Rust message code into the horus Python module.
"""

import subprocess
from pathlib import Path
from typing import List, Optional
import hashlib

from .generator import get_registered_messages, _generate_rust_code, MessageDef


def get_horus_py_root() -> Path:
    """Get the horus_py package root directory."""
    # This file is at horus_py/horus/msggen/builder.py
    # horus_py root is 3 levels up
    return Path(__file__).parent.parent.parent


def get_custom_messages_dir() -> Path:
    """Get the directory for custom message Rust files."""
    return get_horus_py_root() / "src" / "custom_messages"


def get_messages_hash_file() -> Path:
    """Get the file that stores the hash of generated messages."""
    return get_custom_messages_dir() / ".messages_hash"


def compute_messages_hash(messages: List[MessageDef]) -> str:
    """Compute a hash of all message definitions."""
    content = ""
    for msg in sorted(messages, key=lambda m: m.name):
        content += f"{msg.name}:{msg.topic}:"
        for field in msg.fields:
            content += f"{field.name}:{field.rust_type},"
        content += "\n"
    return hashlib.md5(content.encode()).hexdigest()


def check_needs_rebuild() -> bool:
    """Check if custom messages need to be rebuilt."""
    messages = get_registered_messages()
    if not messages:
        return False

    hash_file = get_messages_hash_file()
    if not hash_file.exists():
        return True

    current_hash = compute_messages_hash(messages)
    stored_hash = hash_file.read_text().strip()
    return current_hash != stored_hash


def generate_custom_messages_mod(messages: List[MessageDef]) -> str:
    """Generate the mod.rs file that includes all custom messages."""
    if not messages:
        return """//! Custom messages module (empty)
//! Add custom messages using horus.msggen

use pyo3::prelude::*;

pub fn register_custom_messages(_m: &Bound<'_, PyModule>) -> PyResult<()> {
    // No custom messages defined
    Ok(())
}
"""

    # Generate module declarations and registrations
    mod_decls = []
    use_decls = []
    register_calls = []

    for msg in messages:
        mod_name = msg.name.lower()
        mod_decls.append(f"mod {mod_name};")
        use_decls.append(f"pub use {mod_name}::Py{msg.name};")
        register_calls.append(f"    m.add_class::<Py{msg.name}>()?;")

    return f"""//! Custom messages module (auto-generated)
//! DO NOT EDIT - Generated by horus.msggen

use pyo3::prelude::*;

{chr(10).join(mod_decls)}

{chr(10).join(use_decls)}

pub fn register_custom_messages(m: &Bound<'_, PyModule>) -> PyResult<()> {{
{chr(10).join(register_calls)}
    Ok(())
}}
"""


def build_messages(force: bool = False, verbose: bool = True) -> bool:
    """
    Build all registered custom messages.

    This:
    1. Generates Rust code for each registered message
    2. Creates the mod.rs to include them
    3. Runs maturin to rebuild the Python module

    Args:
        force: Force rebuild even if messages haven't changed
        verbose: Print progress messages

    Returns:
        True if build succeeded
    """
    messages = get_registered_messages()

    if not messages:
        if verbose:
            print("No custom messages registered. Nothing to build.")
        return True

    # Check if rebuild is needed
    if not force and not check_needs_rebuild():
        if verbose:
            print("Custom messages are up to date. Use force=True to rebuild.")
        return True

    if verbose:
        print(f"Building {len(messages)} custom message(s)...")

    # Create custom messages directory
    custom_dir = get_custom_messages_dir()
    custom_dir.mkdir(parents=True, exist_ok=True)

    # Generate each message file
    for msg in messages:
        rust_code = _generate_rust_code(msg)
        output_file = custom_dir / f"{msg.name.lower()}.rs"
        output_file.write_text(rust_code)
        if verbose:
            print(f"  Generated: {output_file.name}")

    # Generate mod.rs
    mod_rs = generate_custom_messages_mod(messages)
    (custom_dir / "mod.rs").write_text(mod_rs)
    if verbose:
        print(f"  Generated: mod.rs")

    # Save hash
    hash_file = get_messages_hash_file()
    hash_file.write_text(compute_messages_hash(messages))

    # Run maturin build
    if verbose:
        print("\nRunning maturin develop...")

    horus_py_root = get_horus_py_root()

    try:
        result = subprocess.run(
            ["maturin", "develop", "--release"],
            cwd=horus_py_root,
            capture_output=not verbose,
            text=True,
        )

        if result.returncode != 0:
            if not verbose:
                print(f"Build failed:\n{result.stderr}")
            return False

        if verbose:
            print("\nBuild successful! Custom messages are now available.")
            print("\nUsage:")
            for msg in messages:
                print(f"  from horus import {msg.name}, Topic")
                print(f"  topic = Topic({msg.name})")

        return True

    except FileNotFoundError:
        print("Error: maturin not found. Install with: pip install maturin")
        return False
