#!/usr/bin/env python3
import sys
import os
import logging
import json
import time
import gi

gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, GObject, GLib

# Add the lib directory to sys.path to find local modules
lib_path = os.path.join(os.path.dirname(os.path.realpath(__file__)), "lib")
sys.path.insert(0, lib_path)

# Import the original indicator class
from indicator_sound_switcher.indicator import SoundSwitcherIndicator, APP_ID, APP_NAME


class Persistence(SoundSwitcherIndicator):
    PERSISTENCE_FILE = os.path.expanduser("~/.config/vx-indicator-sound-switcher.json")

    def __init__(self):
        # We act as a GObject, but we don't call SoundSwitcherIndicator.__init__
        # to avoid GUI overheads (AppIndicator etc).
        GObject.GObject.__init__(self)

        # -- Core Setup (Adapted from SoundSwitcherIndicator.__init__) --

        # Initialise items
        self.cards = {}
        self.sources = {}
        self.source_outputs = {}
        self.sinks = {}
        self.sink_inputs = {}

        self.pa_context = None
        self.pa_context_connected = False
        self.pa_context_failed = False
        self.pa_connecting = False

        # Config setup (needed for PA callbacks to work properly if they access it)
        try:
            self.config_file_name = os.path.join(
                GLib.get_user_config_dir(), APP_ID + ".json"
            )
            # We can't call config_load directly if it relies on self.config being present?
            # No, config_load loads TO self.config usually? No, it returns it.
            # But indicator.__init__ does: self.config = self.config_load()
            # We should do the same to be safe.
            self.config = self.config_load()
            self.config_devices = self.config["devices"]
        except Exception:
            from indicator_sound_switcher.config import Config

            self.config = Config()
            self.config_devices = {}

        # Initialise the PulseAudio interface references
        self.pa_mainloop = None
        self.pa_mainloop_api = None

        # Setup PulseAudio callbacks
        from indicator_sound_switcher.lib_pulseaudio import (
            pa_card_info_cb_t,
            pa_context_notify_cb_t,
            pa_context_subscribe_cb_t,
            pa_context_success_cb_t,
            pa_server_info_cb_t,
            pa_sink_info_cb_t,
            pa_sink_input_info_cb_t,
            pa_source_info_cb_t,
            pa_source_output_info_cb_t,
        )

        self._pacb_card_info = pa_card_info_cb_t(self.pacb_card_info)
        self._pacb_context_notify = pa_context_notify_cb_t(self.pacb_context_notify)
        self._pacb_context_subscribe = pa_context_subscribe_cb_t(
            self.pacb_context_subscribe
        )
        self._pacb_context_success = pa_context_success_cb_t(self.pacb_context_success)
        self._pacb_server_info = pa_server_info_cb_t(self.pacb_server_info)
        self._pacb_sink_info = pa_sink_info_cb_t(self.pacb_sink_info)
        self._pacb_sink_input_info = pa_sink_input_info_cb_t(self.pacb_sink_input_info)
        self._pacb_source_info = pa_source_info_cb_t(self.pacb_source_info)
        self._pacb_source_output_info = pa_source_output_info_cb_t(
            self.pacb_source_output_info
        )

        # Connect to PulseAudio
        # pulseaudio_connect calls menu_setup(), so we need to mock it.
        # It also enables 'pa_connecting'
        self.pulseaudio_connect()

    # -- Overrides to avoid GUI --

    def menu_setup(self):
        """Mock menu setup to do nothing."""
        pass

    def card_create_menu_items(self, card):
        """Mock to avoid creating menu items."""
        pass

    def sink_input_add(self, index, name, sink):
        """Override to avoid GUI updates."""
        self.sink_inputs[index] = name

    def source_output_add(self, index, name):
        """Override to avoid GUI updates."""
        self.source_outputs[index] = name

    # sink_info and source_info might create items for virtual devices.
    # They check self.item_header_outputs which is None by default in our __init__.
    # So they should be safe.

    def restore_persistence(self):
        """Restore the selection from a file."""
        if not os.path.exists(self.PERSISTENCE_FILE):
            logging.info("No persistence file found.")
            return

        try:
            with open(self.PERSISTENCE_FILE, "r") as f:
                data = json.load(f)

            card_name = data.get("card_name")
            port_name = data.get("port_name")

            if not card_name or not port_name:
                return

            logging.info("Restoring persistence: %s, %s", card_name, port_name)

            # Find the card and port
            card, port = self.find_card_port_by_name(card_name, port_name)

            if card and port:
                # Activate it
                self.activate_port(card.index, port.name)
                logging.info("Restored successful.")
            else:
                logging.warning(
                    "Persisted device not found: %s, %s", card_name, port_name
                )

        except Exception as e:
            logging.error("Failed to restore persistence: %s", e)

    def run_restore(self):
        # We need to wait for connection? pulseaudio_connect loops internally until connected or failed.
        # So by the time it returns (if success), we are connected.
        # Then it calls update_pa_items().
        # So we should be ready to restore.

        self.restore_persistence()

        # Shutdown cleanly
        self.pulseaudio_shutdown()


if __name__ == "__main__":
    logging.basicConfig(level=logging.INFO, format="%(levelname)-8s %(message)s")
    try:
        app = Persistence()
        app.run_restore()
    except Exception as e:
        logging.error("Application failed: %s", e)
        sys.exit(1)
