import os
import sys
import json
import urllib.request
import urllib.error
from datetime import datetime, date

# Gets the KEKA_TOKEN from environment variable
KEKA_TOKEN = os.environ.get("KEKA_TOKEN")

def get_cache_file():
    cache_dir = os.environ.get("XDG_CACHE_HOME", os.path.join(os.path.expanduser("~"), ".cache"))
    mlog_dir = os.path.join(cache_dir, "mlog")
    os.makedirs(mlog_dir, exist_ok=True)
    return os.path.join(mlog_dir, "keka_attendance.json")

def to_seconds(time_str):
    if isinstance(time_str, (int, float)):
        return int(time_str * 3600 + 0.5)
    
    time_str = str(time_str).strip()
    if ':' in time_str:
        parts = time_str.split(':')
        h = int(parts[0]) if len(parts) > 0 else 0
        m = int(parts[1]) if len(parts) > 1 else 0
        s = int(parts[2]) if len(parts) > 2 else 0
        return h * 3600 + m * 60 + s
    
    try:
        hours = float(time_str)
        return int(hours * 3600 + 0.5)
    except ValueError:
        raise ValueError(f"unsupported duration format: {time_str}")

def format_hms(total_seconds):
    total_seconds = int(total_seconds)
    hours = total_seconds // 3600
    minutes = (total_seconds % 3600) // 60
    seconds = total_seconds % 60
    return f"{hours:02d}:{minutes:02d}:{seconds:02d}"

def parse_login_time(raw_timestamp):
    if not raw_timestamp or raw_timestamp == "null":
        raise ValueError("Invalid timestamp")
        
    try:
        # Handle epoch time (Unix timestamp)
        if isinstance(raw_timestamp, (int, float)) or str(raw_timestamp).isdigit():
            epoch = int(raw_timestamp)
            if epoch > 9999999999:  # milliseconds to seconds
                epoch = epoch / 1000.0
            return datetime.fromtimestamp(epoch).strftime("%H:%M:%S")
            
        # Handle ISO string
        raw_timestamp = str(raw_timestamp)
        # Simplistic ISO 8601 parsing 
        raw_timestamp = raw_timestamp.replace('Z', '+00:00')
        dt = datetime.fromisoformat(raw_timestamp)
        # Convert to local time
        dt = dt.astimezone()
        return dt.strftime("%H:%M:%S")
    except Exception as e:
        raise ValueError(f"unable to parse login timestamp: {raw_timestamp}")

def fetch_and_cache():
    if not KEKA_TOKEN:
        print("mlog: KEKA_TOKEN environment variable is not set", file=sys.stderr)
        print("Please export KEKA_TOKEN or pass it inline before running the script.", file=sys.stderr)
        sys.exit(1)
        
    url = "https://quid.keka.com/k/attendance/api/mytime/attendance/summary"
    req = urllib.request.Request(url)
    req.add_header("accept", "application/json, text/plain, */*")
    req.add_header("authorization", f"Bearer {KEKA_TOKEN}")
    
    try:
        with urllib.request.urlopen(req) as response:
            data = json.loads(response.read().decode())
    except urllib.error.URLError as e:
        print(f"mlog: failed to fetch data from Keka API: {e}", file=sys.stderr)
        sys.exit(1)
        
    try:
        latest_data = data.get("data", [])[-1]
        effective_hours = latest_data.get("totalEffectiveHours", 0)
        
        time_entries = latest_data.get("timeEntries", [])
        if not time_entries:
            raw_timestamp = None
        else:
            raw_timestamp = time_entries[-1]["actualTimestamp"]
    except (KeyError, IndexError, TypeError):
        print("mlog: unable to parse required fields from Keka response", file=sys.stderr)
        sys.exit(1)
        
    last_login = parse_login_time(raw_timestamp) if raw_timestamp else None
    cache_date = date.today().isoformat()
    
    cache_data = {
        "cache_date": cache_date,
        "effective_hours": effective_hours,
        "last_login": last_login
    }
    
    cache_file = get_cache_file()
    with open(cache_file, "w") as f:
        json.dump(cache_data, f)
        
    return cache_data

def load_cached_or_fetch(action):
    cache_file = get_cache_file()
    cache_date = date.today().isoformat()
    
    if action == "refresh" or not os.path.exists(cache_file):
        return fetch_and_cache()
        
    with open(cache_file, "r") as f:
        try:
            cache_data = json.load(f)
        except json.JSONDecodeError:
            return fetch_and_cache()
            
    # Invalidate cache if it's from a previous day or corrupted
    if cache_data.get("cache_date") != cache_date or "effective_hours" not in cache_data or "last_login" not in cache_data:
        return fetch_and_cache()
        
    return cache_data

def mlog():
    action = sys.argv[1] if len(sys.argv) > 1 else None
    if action and action != "refresh":
        print("Usage: python keka.py [refresh]", file=sys.stderr)
        sys.exit(1)
        
    required_seconds = 27000 # 7.5 hours
    
    payload = load_cached_or_fetch(action)
    cached_effective_hours = payload["effective_hours"]
    last_login = payload.get("last_login")
    
    if not last_login:
        print("No time entries logged for today yet.")
        sys.exit(0)
        
    cached_effective_seconds = to_seconds(cached_effective_hours)
    last_login_seconds = to_seconds(last_login)
    
    now = datetime.now()
    now_seconds = now.hour * 3600 + now.minute * 60 + now.second
    
    # Time elapsed in the current session (since last login)
    elapsed_seconds = now_seconds - last_login_seconds
    if elapsed_seconds < 0:
        elapsed_seconds += 86400
        
    dynamic_effective_seconds = cached_effective_seconds + elapsed_seconds
    
    if dynamic_effective_seconds >= required_seconds:
        dynamic_remaining_seconds = 0
        logout_seconds = now_seconds
    else:
        dynamic_remaining_seconds = required_seconds - dynamic_effective_seconds
        logout_seconds = last_login_seconds + (required_seconds - cached_effective_seconds)
        if logout_seconds >= 86400:
            logout_seconds -= 86400
            
    print(f"Last login: {last_login}")
    print(f"Effective hours: {format_hms(dynamic_effective_seconds)}")
    print(f"Time remaining: {format_hms(dynamic_remaining_seconds)}")
    print(f"Optimistic logout time: {format_hms(logout_seconds)}")

if __name__ == "__main__":
    mlog()
