"""
Time Shell - Temporal Operations for CST Units
===============================================

HEX_ID: 43208FA0
AREA: Physical (43)
COMPONENT: Time (20)
LEVEL: Shell (8F)
INSTANCE: Primary (A0)

Core Principle: t = d/t -> t = sqrt(d)
Time is computed O(1) from distance. The observer samples; the state exists at all t.

Celestial Integration:
    Earth Prime: 6584 (base reference)
    21/80 ratio: Sun gravitational influence
    20/79 ratio: Jupiter-Moon coupling

Commands:
    status      - Time system status
    get HEX     - Get time state of token
    trajectory  - Compute trajectory for token
    dilate      - Apply time dilation to token
    sync        - Sync to epoch zero

Inputs/Outputs:
    status: None -> Dict (constants, celestial primes, ratios)
    get: hex_id:str -> Dict (coords, t, phase, angular_velocity, epoch, k11_level, srl_state)
    trajectory: hex_id:str, steps:int, dt:float, dilation_factor:float -> Dict (path points)
    dilate: hex_id:str, factor:float -> Dict (dilated time state)
    sync: None -> Dict (epoch zero reference)
"""

from __future__ import annotations

import math
import json
import argparse
from typing import Dict, Any, Tuple, Optional
from datetime import datetime

from .._core.constants import PHI, K5, K11, LIGHT_UNIT, MATRIX_SIZE
from .._core import morton


# =============================================================================
# TIME CONSTANTS
# =============================================================================

TIME_UNIT = 1.0 / PHI                    # Base time quantum (~0.618)
PLANCK_TICK = 5.391e-44                  # Planck time in seconds
EPOCH_ZERO_HEX = "2A9E0000"              # Queen hex as t=0 reference

# Celestial Primes
EARTH_PRIME = 6584
SUN_PRIME = 2179
MOON_PRIME = 79
JUPITER_PRIME = 2089

# Celestial Ratios
SUN_EARTH_RATIO = 21 / 80                # 0.2625
JUPITER_MOON_RATIO = 20 / 79             # 0.2532

# Phi depth lookup table (precomputed for O(1))
PHI_DEPTH_TABLE = [PHI ** n for n in range(32)]


# =============================================================================
# CORE FUNCTIONS
# =============================================================================

def hex_to_morton(hex_id: str) -> int:
    """Extract Morton code from hex ID - O(1)."""
    try:
        value = int(hex_id, 16)
        return value & 0xFFFFF  # Lower 20 bits
    except ValueError:
        return 0


def morton_decode_wrapped(m: int) -> Tuple[int, int, int]:
    """Decode Morton to wrapped coordinates."""
    x, y, z = morton.decode(m)
    return (x % MATRIX_SIZE, y % MATRIX_SIZE, z % MATRIX_SIZE)


def time_from_distance(distance: float) -> float:
    """
    Core SRL formula: t = sqrt(d)
    Time is O(1) computable from distance.
    """
    if distance <= 0:
        return 0.0
    return math.sqrt(distance)


def distance_from_time(t: float) -> float:
    """
    Inverse SRL formula: d = t^2
    Distance from time parameter.
    """
    return t * t


def compute_phase(t: float, angular_velocity: float, initial_phase: float = 0.0) -> float:
    """Compute orbital phase at time t."""
    return (initial_phase + t * angular_velocity) % (2 * math.pi)


def compute_position(
    t: float,
    orbital_radius: float,
    angular_velocity: float,
    center: Tuple[float, float, float],
    initial_phase: float = 0.0,
    z_drift: float = 0.0
) -> Tuple[float, float, float]:
    """
    Compute position on epicycle at time t.
    Returns (x, y, z) position.
    """
    phase = compute_phase(t, angular_velocity, initial_phase)
    x = center[0] + orbital_radius * math.cos(phase)
    y = center[1] + orbital_radius * math.sin(phase)
    z = center[2] + z_drift * t
    return (x, y, z)


def compute_velocity(
    t: float,
    orbital_radius: float,
    angular_velocity: float,
    initial_phase: float = 0.0,
    z_drift: float = 0.0
) -> Tuple[float, float, float]:
    """Compute velocity vector at time t."""
    phase = compute_phase(t, angular_velocity, initial_phase)
    vx = -orbital_radius * angular_velocity * math.sin(phase)
    vy = orbital_radius * angular_velocity * math.cos(phase)
    vz = z_drift
    return (vx, vy, vz)


def time_dilation(t: float, factor: float) -> float:
    """
    Apply time dilation.
    factor > 1: time slows (approaching massive object)
    factor < 1: time speeds up (moving away)
    """
    return t * factor


def get_srl_state(k11_level: int) -> str:
    """Map K11 level to SRL state."""
    if k11_level == 0:
        return "ABSORBED"
    elif k11_level > 0:
        if k11_level % 2 == 1:
            return "DIRECT"
        else:
            return "SPIRAL"
    else:  # k11_level < 0
        if abs(k11_level) % 2 == 1:
            return "INVERSE"
        else:
            return "CONVERGENT"


# =============================================================================
# TOKEN TIME OPERATIONS
# =============================================================================

def get_token_time_state(hex_id: str) -> Dict[str, Any]:
    """
    Get temporal state of a token.
    All computed O(1) from hex ID.
    """
    m = hex_to_morton(hex_id)
    x, y, z = morton_decode_wrapped(m)

    # Compute orbital parameters from position
    center = (MATRIX_SIZE // 2, MATRIX_SIZE // 2, MATRIX_SIZE // 2)
    dx, dy, dz = x - center[0], y - center[1], z - center[2]
    orbital_radius = math.sqrt(dx*dx + dy*dy + dz*dz)

    # Angular velocity from phi-normalized distance
    phi_norm = orbital_radius / (MATRIX_SIZE * PHI)
    angular_velocity = PHI / (1 + phi_norm) if phi_norm > 0 else PHI

    # Initial phase from position
    if orbital_radius > 0:
        initial_phase = math.atan2(dy, dx)
    else:
        initial_phase = 0.0

    # Time parameter from distance (SRL formula)
    t = time_from_distance(orbital_radius)

    # K11 level and SRL state
    k11_level = (m % 23) - 11
    srl_state = get_srl_state(k11_level)

    # Epoch time (relative to Queen)
    queen_morton = hex_to_morton(EPOCH_ZERO_HEX)
    epoch = abs(m - queen_morton) / (MATRIX_SIZE ** 3)

    return {
        "hex_id": hex_id,
        "morton": m,
        "coords": (x, y, z),
        "t": t,
        "phase": initial_phase,
        "angular_velocity": angular_velocity,
        "orbital_radius": orbital_radius,
        "epoch": epoch,
        "k11_level": k11_level,
        "srl_state": srl_state,
        "center": center,
        "dilated": False,
        "dilation_factor": 1.0
    }


def compute_trajectory(
    hex_id: str,
    steps: int = 10,
    dt: float = 0.1,
    dilation_factor: float = 1.0
) -> Dict[str, Any]:
    """
    Compute time trajectory for a token.
    Returns positions at each time step.
    """
    state = get_token_time_state(hex_id)

    trajectory = []
    for step in range(steps):
        t = step * dt * dilation_factor

        position = compute_position(
            t,
            state["orbital_radius"],
            state["angular_velocity"],
            state["center"],
            state["phase"],
            z_drift=0.1 * state["k11_level"]
        )

        velocity = compute_velocity(
            t,
            state["orbital_radius"],
            state["angular_velocity"],
            state["phase"],
            z_drift=0.1 * state["k11_level"]
        )

        phase = compute_phase(t, state["angular_velocity"], state["phase"])

        trajectory.append({
            "step": step,
            "t": round(t, 4),
            "position": tuple(round(p, 2) for p in position),
            "phase": round(phase, 4),
            "velocity": tuple(round(v, 4) for v in velocity)
        })

    return {
        "hex_id": hex_id,
        "initial_state": state,
        "steps": steps,
        "dt": dt,
        "dilation_factor": dilation_factor,
        "trajectory": trajectory,
        "computed_at": datetime.now().isoformat()
    }


def get_system_status() -> Dict[str, Any]:
    """Get time shell system status."""
    return {
        "shell": "time_shell",
        "version": "1.0.0",
        "hex_id": "43208FA0",
        "status": "ACTIVE",
        "constants": {
            "PHI": PHI,
            "TIME_UNIT": TIME_UNIT,
            "PLANCK_TICK": PLANCK_TICK,
            "EPOCH_ZERO": EPOCH_ZERO_HEX
        },
        "celestial_primes": {
            "earth": EARTH_PRIME,
            "sun": SUN_PRIME,
            "moon": MOON_PRIME,
            "jupiter": JUPITER_PRIME
        },
        "ratios": {
            "sun_earth": SUN_EARTH_RATIO,
            "jupiter_moon": JUPITER_MOON_RATIO,
            "21_80": "21/80 = Sun gravitational influence",
            "20_79": "20/79 = Jupiter-Moon coupling"
        },
        "srl_formula": "t = sqrt(d) | d = t^2",
        "phi_depth_levels": len(PHI_DEPTH_TABLE),
        "timestamp": datetime.now().isoformat()
    }


def sync_to_epoch_zero() -> Dict[str, Any]:
    """
    Synchronize time reference to epoch zero (Queen).
    Returns calibration data.
    """
    queen_state = get_token_time_state(EPOCH_ZERO_HEX)
    return {
        "epoch_zero": EPOCH_ZERO_HEX,
        "queen_state": queen_state,
        "sync_time": datetime.now().isoformat(),
        "message": "All tokens now referenced to Queen epoch t=0"
    }


# =============================================================================
# SHELL CLASS
# =============================================================================

class TimeShell:
    """Time Shell - Temporal Operations for CST Units."""

    def __init__(self):
        self.name = "time"
        self.hex_id = "43208FA0"
        self.version = "1.0.0"

    def status(self) -> Dict[str, Any]:
        """Get time system status."""
        return get_system_status()

    def get(self, hex_id: str) -> Dict[str, Any]:
        """Get time state of token."""
        return get_token_time_state(hex_id)

    def trajectory(self, hex_id: str, steps: int = 10, dt: float = 0.1,
                   dilation_factor: float = 1.0) -> Dict[str, Any]:
        """Compute trajectory for token."""
        return compute_trajectory(hex_id, steps, dt, dilation_factor)

    def dilate(self, hex_id: str, factor: float = 1.0) -> Dict[str, Any]:
        """Apply time dilation to token."""
        state = get_token_time_state(hex_id)
        state["dilated"] = True
        state["dilation_factor"] = factor
        state["t_dilated"] = time_dilation(state["t"], factor)
        return state

    def sync(self) -> Dict[str, Any]:
        """Sync to epoch zero."""
        return sync_to_epoch_zero()

    def execute(self, command: str, args: Dict[str, Any] = None) -> Dict[str, Any]:
        """Execute shell command."""
        args = args or {}

        if command == "status":
            return self.status()
        elif command == "get":
            return self.get(args.get("hex_id", "2A9E0100"))
        elif command == "trajectory":
            return self.trajectory(
                args.get("hex_id", "2A9E0100"),
                args.get("steps", 10),
                args.get("dt", 0.1),
                args.get("dilation_factor", 1.0)
            )
        elif command == "dilate":
            return self.dilate(
                args.get("hex_id", "2A9E0100"),
                args.get("factor", 1.0)
            )
        elif command == "sync":
            return self.sync()
        else:
            return {"error": f"Unknown command: {command}"}

    def run(self, command: str, *args, as_json: bool = False) -> Any:
        """Run a Time shell command (CLI interface)."""
        result = self.execute(command, {"hex_id": args[0] if args else "2A9E0100"})
        if as_json:
            return json.dumps(result, indent=2)
        return result


# =============================================================================
# CLI INTERFACE
# =============================================================================

def main():
    parser = argparse.ArgumentParser(
        description='Time Shell - Temporal Operations for CST Units',
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
    python -m cubesquare.shells.time --status
    python -m cubesquare.shells.time --get 2A9E0100
    python -m cubesquare.shells.time --trajectory 2A9E0100 --steps 20
    python -m cubesquare.shells.time --dilate 2A9E0100 --factor 1.5
    python -m cubesquare.shells.time --sync

Core Formula: t = sqrt(d) - Time is O(1) computable from distance.
"""
    )

    parser.add_argument('--status', action='store_true', help='Time system status')
    parser.add_argument('--get', metavar='HEX', help='Get time state of token')
    parser.add_argument('--trajectory', metavar='HEX', help='Compute trajectory')
    parser.add_argument('--steps', type=int, default=10, help='Trajectory steps (default: 10)')
    parser.add_argument('--dt', type=float, default=0.1, help='Time step (default: 0.1)')
    parser.add_argument('--dilate', metavar='HEX', help='Apply time dilation to token')
    parser.add_argument('--factor', type=float, default=1.0, help='Dilation factor (default: 1.0)')
    parser.add_argument('--sync', action='store_true', help='Sync to epoch zero')
    parser.add_argument('--json', action='store_true', help='JSON output')

    args = parser.parse_args()

    shell = TimeShell()
    result = None

    if args.status:
        result = shell.status()
    elif args.get:
        result = shell.get(args.get)
    elif args.trajectory:
        result = shell.trajectory(args.trajectory, args.steps, args.dt, args.factor)
    elif args.dilate:
        result = shell.dilate(args.dilate, args.factor)
    elif args.sync:
        result = shell.sync()
    else:
        parser.print_help()
        return

    if result:
        print(json.dumps(result, indent=2, default=str))


if __name__ == '__main__':
    main()
