#!/usr/bin/env python3
# -*- coding: utf-8 -*-

# Fenrir TTY screen reader
# By Chrys, Storm Dragon, and contributors.

import errno
import json
import os
import tempfile
import time


INSTANCE_TIMEOUT_SEC = 30.0


def get_registry_dir():
    return os.path.join(tempfile.gettempdir(), "fenrirscreenreader-instances")


def get_instance_file(pid=None):
    if pid is None:
        pid = os.getpid()
    return os.path.join(get_registry_dir(), f"{pid}.json")


def write_instance(instance_data):
    registry_dir = get_registry_dir()
    os.makedirs(registry_dir, mode=0o755, exist_ok=True)
    os.chmod(registry_dir, 0o755)
    instance_data["updated_at"] = time.time()
    instance_path = get_instance_file(instance_data.get("pid"))
    with open(instance_path, "w", encoding="utf-8") as instance_file:
        json.dump(instance_data, instance_file, sort_keys=True)
        instance_file.write("\n")
    os.chmod(instance_path, 0o644)


def remove_instance(pid=None):
    try:
        os.unlink(get_instance_file(pid))
    except FileNotFoundError:
        pass


def process_exists(pid):
    try:
        os.kill(pid, 0)
        return True
    except OSError as e:
        if e.errno == errno.EPERM:
            return True
        return False


def list_instances():
    registry_dir = get_registry_dir()
    instances = []
    try:
        instance_files = os.listdir(registry_dir)
    except FileNotFoundError:
        return instances

    now = time.time()
    for instance_name in instance_files:
        instance_path = os.path.join(registry_dir, instance_name)
        try:
            with open(instance_path, "r", encoding="utf-8") as instance_file:
                instance_data = json.load(instance_file)
            pid = int(instance_data.get("pid", 0))
            updated_at = float(instance_data.get("updated_at", 0))
        except (OSError, ValueError, TypeError, json.JSONDecodeError):
            continue

        if not pid or not process_exists(pid) or now - updated_at > INSTANCE_TIMEOUT_SEC:
            try:
                os.unlink(instance_path)
            except OSError:
                pass
            continue
        instances.append(instance_data)

    return sorted(instances, key=lambda instance: int(instance.get("pid", 0)))
